Upgrade dagger2 to 347cfe1352469381f4391091e8bfa242214c68cc am: 311df9bffa

Original change: https://android-review.googlesource.com/c/platform/external/dagger2/+/3446311

Change-Id: I89f8b73361cb8789be8e89ff1601a372ac883e49
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.allstar/binary_artifacts.yaml b/.allstar/binary_artifacts.yaml
index 38e18be..61d0f0b 100644
--- a/.allstar/binary_artifacts.yaml
+++ b/.allstar/binary_artifacts.yaml
@@ -9,3 +9,5 @@
 - java/dagger/internal/codegen/kythe/kythe_plugin_deploy.jar  # TODO(b/235380696): remove this
 - java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar
 - java/dagger/internal/codegen/xprocessing/xprocessing.jar
+- tools/jarjar/test/test-library1.jar
+- tools/jarjar/test/test-library2.jar
\ No newline at end of file
diff --git a/.bazelrc b/.bazelrc
index ecd54a5..e02e83d 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -6,3 +6,27 @@
 # TODO(ronshapiro): explore how much work it would be to reenable this
 build --javacopt="-Xep:BetaApi:OFF"
 build --host_javacopt="-Xep:BetaApi:OFF"
+
+# Note: This flag is required to prevent actions from clashing with each other
+# when reading/writing tmp files. Without this flag we get errors like:
+#
+#  Error: Cannot use file /tmp/hsperfdata_runner/12 because it is locked by
+#         another process
+#
+# This flag will be enabled by default in Bazel 7.0.0, but for now we enable it
+# manually. For more details: https://github.com/bazelbuild/bazel/issues/3236.
+build --incompatible_sandbox_hermetic_tmp
+
+# Sets the JDK for compiling sources and executing tests.
+build --java_language_version=18
+build --tool_java_language_version=18
+build --java_runtime_version=remotejdk_18
+build --tool_java_runtime_version=remotejdk_18
+
+# Default source/target versions.
+build --javacopt="-source 8 -target 8"
+
+# Workaround for https://openjdk.java.net/jeps/411.
+# See https://github.com/bazelbuild/bazel/issues/14502#issuecomment-1018366245.
+build --jvmopt="-Djava.security.manager=allow"
+build --jvmopt="--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"
diff --git a/.bazelversion b/.bazelversion
new file mode 100644
index 0000000..c0be8a7
--- /dev/null
+++ b/.bazelversion
@@ -0,0 +1 @@
+6.4.0
\ No newline at end of file
diff --git a/.github/actions/artifact-android-emulator-tests/action.yml b/.github/actions/artifact-android-emulator-tests/action.yml
index 2fc2987..93494f0 100644
--- a/.github/actions/artifact-android-emulator-tests/action.yml
+++ b/.github/actions/artifact-android-emulator-tests/action.yml
@@ -10,9 +10,9 @@
   using: "composite"
   steps:
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
@@ -21,12 +21,12 @@
         restore-keys: |
           ${{ runner.os }}-gradle-
     - name: 'Download local snapshot for tests'
-      uses: actions/download-artifact@v3
+      uses: actions/download-artifact@v4
       with:
         name: local-snapshot
         path: ~/.m2/repository/com/google/dagger
     - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
         distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
         java-version: '${{ env.USE_JAVA_VERSION }}'
@@ -38,7 +38,7 @@
         script: ./util/run-local-emulator-tests.sh
     - name: 'Upload test reports (API ${{ inputs.api-level }})'
       if: ${{ always() }}
-      uses: actions/upload-artifact@v3
+      uses: actions/upload-artifact@v4
       with:
         name: androidTests-report-api-${{ inputs.api-level }}
         path: ${{ github.workspace }}/**/build/reports/androidTests/connected/*
diff --git a/.github/actions/artifact-android-local-tests/action.yml b/.github/actions/artifact-android-local-tests/action.yml
index c4b24eb..b16ab13 100644
--- a/.github/actions/artifact-android-local-tests/action.yml
+++ b/.github/actions/artifact-android-local-tests/action.yml
@@ -7,9 +7,7 @@
     required: true
     type: choice
     options:
-      - '7.0.0'
-      - '7.1.2'
-      - '8.1.0'
+      - '8.1.1'
   jdk:
     description: 'The version of JDK to test with.'
     required: true
@@ -22,9 +20,9 @@
   using: "composite"
   steps:
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
@@ -33,12 +31,12 @@
         restore-keys: |
           ${{ runner.os }}-gradle-
     - name: 'Download local snapshot for tests'
-      uses: actions/download-artifact@v3
+      uses: actions/download-artifact@v4
       with:
         name: local-snapshot
         path: ~/.m2/repository/com/google/dagger
     - name: 'Install Java ${{ inputs.jdk }}'
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
         distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
         java-version: '${{ inputs.jdk }}'
@@ -47,7 +45,7 @@
       shell: bash
     - name: 'Upload test reports (AGP ${{ inputs.agp }})'
       if: ${{ always() }}
-      uses: actions/upload-artifact@v3
+      uses: actions/upload-artifact@v4
       with:
         name: tests-reports-agp-${{ inputs.agp }}
         path: ${{ github.workspace }}/**/build/reports/tests/*
diff --git a/.github/actions/artifact-java-local-tests/action.yml b/.github/actions/artifact-java-local-tests/action.yml
index e3cf770..bfe997a 100644
--- a/.github/actions/artifact-java-local-tests/action.yml
+++ b/.github/actions/artifact-java-local-tests/action.yml
@@ -5,9 +5,9 @@
   using: "composite"
   steps:
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
@@ -16,7 +16,7 @@
         restore-keys: |
           ${{ runner.os }}-gradle-
     - name: 'Download local snapshot for tests'
-      uses: actions/download-artifact@v3
+      uses: actions/download-artifact@v4
       with:
         name: local-snapshot
         path: ~/.m2/repository/com/google/dagger
diff --git a/.github/actions/artifact-verification-tests/action.yml b/.github/actions/artifact-verification-tests/action.yml
new file mode 100644
index 0000000..30b44fd
--- /dev/null
+++ b/.github/actions/artifact-verification-tests/action.yml
@@ -0,0 +1,25 @@
+name: 'Artifact verification tests'
+description: 'Runs verification tests on the Dagger LOCAL-SNAPSHOT artifacts.'
+
+runs:
+  using: "composite"
+  steps:
+    - name: 'Check out repository'
+      uses: actions/checkout@v4
+    - name: 'Cache Gradle files'
+      uses: actions/cache@v4
+      with:
+        path: |
+          ~/.gradle/caches
+          ~/.gradle/wrapper
+        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+        restore-keys: |
+          ${{ runner.os }}-gradle-
+    - name: 'Download local snapshot for tests'
+      uses: actions/download-artifact@v4
+      with:
+        name: local-snapshot
+        path: ~/.m2/repository/com/google/dagger
+    - name: 'Validate artifact jars'
+      run: ./util/validate-artifacts.sh
+      shell: bash
diff --git a/.github/actions/bazel-build/action.yml b/.github/actions/bazel-build/action.yml
index c464dfe..ab820b4 100644
--- a/.github/actions/bazel-build/action.yml
+++ b/.github/actions/bazel-build/action.yml
@@ -5,14 +5,14 @@
   using: "composite"
   steps:
     - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
         distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
         java-version: '${{ env.USE_JAVA_VERSION }}'
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache Bazel files'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: ~/.cache/bazel
         key: ${{ runner.os }}-bazel-build-${{ github.sha }}
@@ -28,7 +28,7 @@
       run: ./util/install-local-snapshot.sh
       shell: bash
     - name: 'Upload local snapshot for tests'
-      uses: actions/upload-artifact@v3
+      uses: actions/upload-artifact@v4
       with:
         name: local-snapshot
         path: ~/.m2/repository/com/google/dagger
diff --git a/.github/actions/bazel-test/action.yml b/.github/actions/bazel-test/action.yml
index d84f061..9f82546 100644
--- a/.github/actions/bazel-test/action.yml
+++ b/.github/actions/bazel-test/action.yml
@@ -5,14 +5,14 @@
   using: "composite"
   steps:
     - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
         distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
         java-version: '${{ env.USE_JAVA_VERSION }}'
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache local Maven repository'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: |
           ~/.m2/repository
@@ -21,7 +21,7 @@
         restore-keys: |
           ${{ runner.os }}-maven-
     - name: 'Cache Bazel files'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: ~/.cache/bazel
         # Note: we could use the same key as bazel-build, but we separate them
@@ -31,7 +31,7 @@
         restore-keys: |
           ${{ runner.os }}-bazel-test-
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
diff --git a/.github/actions/build-gradle-plugin/action.yml b/.github/actions/build-gradle-plugin/action.yml
index 4fb3293..31a5367 100644
--- a/.github/actions/build-gradle-plugin/action.yml
+++ b/.github/actions/build-gradle-plugin/action.yml
@@ -10,14 +10,14 @@
   using: "composite"
   steps:
     - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
           distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
           java-version: '${{ env.USE_JAVA_VERSION }}'
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache local Maven repository'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: |
           ~/.m2/repository
@@ -26,14 +26,14 @@
         restore-keys: |
           ${{ runner.os }}-maven-
     - name: 'Cache Bazel files'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: ~/.cache/bazel
         key: ${{ runner.os }}-bazel-build-${{ github.sha }}
         restore-keys: |
           ${{ runner.os }}-bazel-build-
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
diff --git a/.github/actions/cleanup-caches/action.yml b/.github/actions/cleanup-caches/action.yml
index 294d624..0197d8f 100644
--- a/.github/actions/cleanup-caches/action.yml
+++ b/.github/actions/cleanup-caches/action.yml
@@ -5,7 +5,7 @@
   using: "composite"
   steps:
       - name: 'Check out repository'
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
       - name: 'Cleanup caches'
         run: python ./util/cleanup-github-caches.py
         shell: bash
diff --git a/.github/actions/gradle-build/action.yml b/.github/actions/gradle-build/action.yml
new file mode 100644
index 0000000..14d372c
--- /dev/null
+++ b/.github/actions/gradle-build/action.yml
@@ -0,0 +1,25 @@
+name: 'Gradle Build'
+description: 'Builds artifacts using Gradle.'
+
+runs:
+  using: "composite"
+  steps:
+  - name: 'Install Java ${{ env.USE_JAVA_VERSION_FOR_GRADLE }}'
+    uses: actions/setup-java@v4
+    with:
+      distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
+      java-version: '${{ env.USE_JAVA_VERSION_FOR_GRADLE }}'
+  - name: 'Check out repository'
+    uses: actions/checkout@v4
+  - name: 'Cache Gradle files'
+    uses: actions/cache@v4
+    with:
+      path: |
+        ~/.gradle/caches
+        ~/.gradle/wrapper
+      key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+      restore-keys: |
+        ${{ runner.os }}-gradle-
+  - name: 'Build Gradle version'
+    run: ./util/build-gradle.sh
+    shell: bash
diff --git a/.github/actions/prechecks/action.yml b/.github/actions/prechecks/action.yml
index 09dc5d9..1a04552 100644
--- a/.github/actions/prechecks/action.yml
+++ b/.github/actions/prechecks/action.yml
@@ -11,7 +11,7 @@
       with:
         access_token: ${{ github.token }}
     - name: 'Check out gh-pages repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
       with:
         ref: 'refs/heads/gh-pages'
         path: gh-pages
@@ -21,7 +21,7 @@
       env:
         GH_TOKEN: ${{ github.token }}
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cleanup caches'
       run: python ./util/cleanup-github-caches.py
       shell: bash
diff --git a/.github/actions/test-gradle-plugin/action.yml b/.github/actions/test-gradle-plugin/action.yml
index bd57472..3205174 100644
--- a/.github/actions/test-gradle-plugin/action.yml
+++ b/.github/actions/test-gradle-plugin/action.yml
@@ -4,15 +4,15 @@
 runs:
   using: "composite"
   steps:
-    - name: 'Install Java ${{ env.USE_JAVA_VERSION_FOR_PLUGIN }}'
-      uses: actions/setup-java@v3
+    - name: 'Install Java ${{ env.USE_JAVA_VERSION_FOR_GRADLE_PLUGIN }}'
+      uses: actions/setup-java@v4
       with:
         distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
-        java-version: '${{ env.USE_JAVA_VERSION_FOR_PLUGIN }}'
+        java-version: '${{ env.USE_JAVA_VERSION_FOR_GRADLE_PLUGIN }}'
     - name: 'Check out repository'
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
     - name: 'Cache local Maven repository'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: |
           ~/.m2/repository
@@ -21,14 +21,14 @@
         restore-keys: |
           ${{ runner.os }}-maven-
     - name: 'Cache Bazel files'
-      uses: actions/cache@v3
+      uses: actions/cache@v4
       with:
         path: ~/.cache/bazel
         key: ${{ runner.os }}-bazel-build-${{ github.sha }}
         restore-keys: |
           ${{ runner.os }}-bazel-build-
     - name: 'Cache Gradle files'
-      uses: actions/cache@v2
+      uses: actions/cache@v4
       with:
         path: |
           ~/.gradle/caches
@@ -37,7 +37,7 @@
         restore-keys: |
           ${{ runner.os }}-gradle-
     - name: 'Download local snapshot for tests'
-      uses: actions/download-artifact@v3
+      uses: actions/download-artifact@v4
       with:
         name: local-snapshot
         path: ~/.m2/repository/com/google/dagger
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d50fcec..d0d89f4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,11 +11,10 @@
 env:
   USE_JAVA_DISTRIBUTION: 'zulu'
   USE_JAVA_VERSION: '11'
-  # This is required by AGP 8.3+.
-  USE_JAVA_VERSION_FOR_PLUGIN: '17'
-  # Our Bazel builds currently rely on 6.4.0. The version is set via
-  # baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
-  USE_BAZEL_VERSION: '6.4.0'
+  # This is required by Gradle 8.0+.
+  USE_JAVA_VERSION_FOR_GRADLE_PLUGIN: '17'
+  # Required by JDK Toolchain Configuration
+  USE_JAVA_VERSION_FOR_GRADLE: '18'
   # The default Maven 3.9.0 has a regression so we manually install 3.8.7.
   # https://issues.apache.org/jira/browse/MNG-7679
   USE_MAVEN_VERSION: '3.8.7'
@@ -25,37 +24,52 @@
     name: 'Validate Dagger version'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/prechecks
   bazel-build:
     name: 'Bazel build'
     needs: validate-latest-dagger-version
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/bazel-build
   bazel-test:
     name: 'Bazel tests'
     needs: validate-latest-dagger-version
     runs-on:
-      group: large-runner
+      group: large-runner-group
       labels: ubuntu-22.04-16core
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/bazel-test
+  gradle-build:
+    name: 'Gradle build'
+    runs-on:
+      group: large-runner-group
+      labels: ubuntu-22.04-16core
+    steps:
+    - uses: actions/checkout@v4
+    - uses: ./.github/actions/gradle-build
+  artifact-verification-tests:
+    name: 'Artifact verification tests'
+    needs: bazel-build
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: ./.github/actions/artifact-verification-tests
   artifact-java-local-tests:
     name: 'Artifact Java local tests'
     needs: bazel-build
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/artifact-java-local-tests
   test-gradle-plugin:
     name: 'Test Hilt Gradle plugin'
     needs: bazel-build
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/test-gradle-plugin
   artifact-android-local-tests:
     name: 'Artifact Android local tests (AGP ${{ matrix.agp }})'
@@ -64,14 +78,10 @@
     strategy:
       matrix:
         include:
-          - agp: '7.0.0'
-            jdk: '11'
-          - agp: '7.1.2'
-            jdk: '11'
-          - agp: '8.1.0'
+          - agp: '8.1.1'
             jdk: '17'
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/artifact-android-local-tests
         with:
           agp: '${{ matrix.agp }}'
@@ -89,7 +99,7 @@
       matrix: # Run on 16 (PreL), 21 (L), and 26 (O).
         api-level: [16, 21, 26, 30]
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/artifact-android-emulator-tests
         timeout-minutes: 35
         with:
@@ -98,12 +108,18 @@
     name: 'Publish snapshot'
     # TODO(bcorso): Consider also waiting on artifact-android-emulator-tests
     # and artifact-android-emulator-legacy-api-tests after checking flakiness.
-    needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin]
+    needs: [
+      bazel-test,
+      artifact-verification-tests,
+      artifact-java-local-tests,
+      artifact-android-local-tests,
+      test-gradle-plugin
+    ]
     if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
     runs-on: ubuntu-latest
     steps:
       - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-        uses: actions/setup-java@v3
+        uses: actions/setup-java@v4
         with:
           distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
           java-version: '${{ env.USE_JAVA_VERSION }}'
@@ -111,9 +127,9 @@
           server-username: CI_DEPLOY_USERNAME
           server-password: CI_DEPLOY_PASSWORD
       - name: 'Check out repository'
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
       - name: 'Cache local Maven repository'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.m2/repository
@@ -122,14 +138,14 @@
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: 'Cache Bazel files'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: ~/.cache/bazel
           key: ${{ runner.os }}-bazel-build-${{ github.sha }}
           restore-keys: |
             ${{ runner.os }}-bazel-build-
       - name: 'Cache Gradle files'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.gradle/caches
@@ -169,7 +185,7 @@
     needs: bazel-build
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/build-gradle-plugin
         with:
           agp: '+'
@@ -177,8 +193,14 @@
     name: 'Clean up GitHub Action caches'
     # TODO(bcorso): Consider also waiting on artifact-android-emulator-tests
     # and artifact-android-emulator-legacy-api-tests after checking flakiness.
-    needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin]
+    needs: [
+      bazel-test,
+      artifact-verification-tests,
+      artifact-java-local-tests,
+      artifact-android-local-tests,
+      test-gradle-plugin
+    ]
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/cleanup-caches
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b16c0d5..9557611 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,11 +10,10 @@
 env:
   USE_JAVA_DISTRIBUTION: 'zulu'
   USE_JAVA_VERSION: '11'
-  # This is required by AGP 8.3+.
-  USE_JAVA_VERSION_FOR_PLUGIN: '17'
-  # Our Bazel builds currently rely on 6.4.0. The version is set via
-  # baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
-  USE_BAZEL_VERSION: '6.4.0'
+  # This is required by Gradle 8.0+.
+  USE_JAVA_VERSION_FOR_GRADLE_PLUGIN: '17'
+  # Required by JDK Toolchain Configuration
+  USE_JAVA_VERSION_FOR_GRADLE: '18'
   DAGGER_RELEASE_VERSION: "${{ github.event.inputs.dagger_release_version }}"
   # The default Maven 3.9.0 has a regression so we manually install 3.8.7.
   # https://issues.apache.org/jira/browse/MNG-7679
@@ -27,37 +26,44 @@
     name: 'Validate Dagger version'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/prechecks
   bazel-build:
     name: 'Bazel build'
     needs: validate-latest-dagger-version
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/bazel-build
   bazel-test:
     name: 'Bazel tests'
     needs: validate-latest-dagger-version
     runs-on:
-      group: large-runner
+      group: large-runner-group
       labels: ubuntu-22.04-16core
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/bazel-test
+  artifact-verification-tests:
+    name: 'Artifact verification tests'
+    needs: bazel-build
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: ./.github/actions/artifact-verification-tests
   artifact-java-local-tests:
     name: 'Artifact Java local tests'
     needs: bazel-build
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/artifact-java-local-tests
   test-gradle-plugin:
     name: 'Test Hilt Gradle plugin'
     needs: bazel-build
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/test-gradle-plugin
   artifact-android-local-tests:
     name: 'Artifact Android local tests (AGP ${{ matrix.agp }})'
@@ -66,25 +72,27 @@
     strategy:
       matrix:
         include:
-          - agp: '7.0.0'
-            jdk: '11'
-          - agp: '7.1.2'
-            jdk: '11'
-          - agp: '8.1.0'
+          - agp: '8.1.1'
             jdk: '17'
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/artifact-android-local-tests
         with:
           agp: '${{ matrix.agp }}'
           jdk: '${{ matrix.jdk }}'
   publish-artifacts:
     name: 'Publish Artifact'
-    needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin]
+    needs: [
+      bazel-test,
+      artifact-verification-tests,
+      artifact-java-local-tests,
+      artifact-android-local-tests,
+      test-gradle-plugin
+    ]
     runs-on: ubuntu-latest
     steps:
       - name: 'Install Java ${{ env.USE_JAVA_VERSION }}'
-        uses: actions/setup-java@v3
+        uses: actions/setup-java@v4
         with:
           distribution: '${{ env.USE_JAVA_DISTRIBUTION }}'
           java-version: '${{ env.USE_JAVA_VERSION }}'
@@ -94,9 +102,9 @@
           gpg-private-key: ${{ secrets.CI_GPG_PRIVATE_KEY }}
           gpg-passphrase: CI_GPG_PASSPHRASE
       - name: 'Check out repository'
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
       - name: 'Cache local Maven repository'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.m2/repository
@@ -105,14 +113,14 @@
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: 'Cache Bazel files'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: ~/.cache/bazel
           key: ${{ runner.os }}-bazel-build-${{ github.sha }}
           restore-keys: |
             ${{ runner.os }}-bazel-build-
       - name: 'Cache Gradle files'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.gradle/caches
diff --git a/Android.bp b/Android.bp
index deb6e01..f14eb2c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -77,8 +77,12 @@
 
     libs: [
         "guava",
+        "jspecify",
         "jsr330",
     ],
+    static_libs: [
+        "jakarta.inject",
+    ],
     apex_available: [
         "//apex_available:platform",
         "com.android.adservices",
@@ -152,6 +156,7 @@
 
     srcs: [
         "java/dagger/internal/codegen/**/*.java",
+        "java/dagger/internal/codegen/**/*.kt",
         "java/dagger/internal/codegen/**/*.proto",
 
         "java/dagger/model/*.java",
@@ -172,13 +177,14 @@
         "dagger2-room-compiler-processing",
         "google_java_format",
         "guava",
+        "jakarta.inject",
         "javapoet",
         "jsr330",
+        "kotlin_metadata_jvm",
         "kotlin_symbol_processing_api",
         "kotlin-stdlib",
         "kotlin-stdlib-jdk8",
         "kotlinpoet",
-        "kotlinx_metadata_jvm",
     ],
 
     libs: [
@@ -507,8 +513,8 @@
         "dagger2",
         "javapoet",
         "jsr330",
+        "kotlin_metadata_jvm",
         "kotlin-stdlib",
-        "kotlinx_metadata_jvm",
         "dagger2-android-annotation-stubs",
     ],
     // shade guava to avoid conflicts with guava embedded in Error Prone.
diff --git a/BUILD b/BUILD
index 2c70b01..6650ea6 100644
--- a/BUILD
+++ b/BUILD
@@ -12,25 +12,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@rules_java//java:defs.bzl", "java_library")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
 load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "define_kt_toolchain")
+load("@rules_java//java:defs.bzl", "java_library")
+load("//tools/jarjar:jarjar.bzl", "jarjar_library")
+load("//tools/javadoc:javadoc.bzl", "javadoc_library")
 
 package(default_visibility = ["//visibility:public"])
 
-define_kt_toolchain(
-    name = "kotlin_toolchain",
-    api_version = "1.4",
-    jvm_target = "1.8",
-    language_version = "1.4",
-)
-
 package_group(
     name = "src",
     packages = ["//..."],
 )
 
+define_kt_toolchain(
+    name = "kotlin_toolchain",
+    api_version = "1.6",
+    jvm_target = "1.8",
+    language_version = "1.6",
+)
+
 java_library(
     name = "dagger_with_compiler",
     exported_plugins = ["//java/dagger/internal/codegen:component-codegen"],
@@ -116,7 +116,7 @@
         "//java/dagger/producers:producers-srcs",
         "//java/dagger/spi:spi-srcs",
     ],
-    android_api_level = 32,
+    android_api_level = 34,
     # TODO(ronshapiro): figure out how to specify the version number for release builds
     doctitle = "Dagger Dependency Injection API",
     exclude_packages = [
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8975bcb..d2ef1ba 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -44,9 +44,9 @@
             [download](https://developer.android.com/studio#command-tools)
             and unzip it first.
         *   Install the necessary components. For example, under Linux, run:
-            `$ANDROID_HOME/tools/bin/sdkmanager "platforms;android-32" "build-tools;32.0.0"`
+            `$ANDROID_HOME/tools/bin/sdkmanager "platforms;android-34" "build-tools;34.0.0"`
             *   If you skip this step, you will see an error similar to
-                `ERROR: missing input file '@androidsdk//:build-tools/32.0.0/aapt'`.
+                `ERROR: missing input file '@androidsdk//:build-tools/34.0.0/aapt'`.
             *   You may also need to run `bazel sync`.
 *   Run tests with `bazel test <target>`, or `bazel test //...` to run all
     tests.
diff --git a/METADATA b/METADATA
index 3511a6c..4746378 100644
--- a/METADATA
+++ b/METADATA
@@ -1,20 +1,20 @@
 # This project was upgraded with external_updater.
 # Usage: tools/external_updater/updater.sh update external/dagger2
-# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
 
 name: "dagger2"
 description: "A fast dependency injector for Android and Java."
 third_party {
   license_type: NOTICE
   last_upgrade_date {
-    year: 2024
-    month: 3
-    day: 5
+    year: 2025
+    month: 1
+    day: 10
   }
   homepage: "https://dagger.dev"
   identifier {
     type: "Git"
     value: "https://github.com/google/dagger"
-    version: "dagger-2.51"
+    version: "347cfe1352469381f4391091e8bfa242214c68cc"
   }
 }
diff --git a/README.md b/README.md
index 4f5c014..ae1ca4a 100644
--- a/README.md
+++ b/README.md
@@ -38,8 +38,8 @@
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
-DAGGER_TAG = "2.50"
-DAGGER_SHA = "764993ba2465551c181b84b47e467f86fb367d8c0cd50154bd5519a4afb57753"
+DAGGER_TAG = "2.55"
+DAGGER_SHA = "ad2272bb59f4b15b9f1c3dad9ec806af7b75bcf5f04e83974dad8e65c581bba4"
 http_archive(
     name = "dagger",
     strip_prefix = "dagger-dagger-%s" % DAGGER_TAG,
diff --git a/WORKSPACE b/WORKSPACE
index 0e93e98..e84385e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
 #############################
@@ -46,6 +47,26 @@
 
 bazel_skylib_workspace()
 
+#############################
+# Load rules_java repository
+#############################
+
+http_archive(
+    name = "rules_java",
+    sha256 = "c73336802d0b4882e40770666ad055212df4ea62cfa6edf9cb0f9d29828a0934",
+    url = "https://github.com/bazelbuild/rules_java/releases/download/5.3.5/rules_java-5.3.5.tar.gz",
+)
+
+#############################
+# Load Android Sdk
+#############################
+
+android_sdk_repository(
+    name = "androidsdk",
+    api_level = 34,
+    build_tools_version = "34.0.0",
+)
+
 ####################################################
 # Load Protobuf repository (needed by bazel-common)
 ####################################################
@@ -68,21 +89,6 @@
 rules_proto_toolchains()
 
 #############################
-# Load Bazel-Common repository
-#############################
-
-http_archive(
-    name = "google_bazel_common",
-    sha256 = "82a49fb27c01ad184db948747733159022f9464fc2e62da996fa700594d9ea42",
-    strip_prefix = "bazel-common-2a6b6406e12208e02b2060df0631fb30919080f3",
-    urls = ["https://github.com/google/bazel-common/archive/2a6b6406e12208e02b2060df0631fb30919080f3.zip"],
-)
-
-load("@google_bazel_common//:workspace_defs.bzl", "google_common_workspace_rules")
-
-google_common_workspace_rules()
-
-#############################
 # Load Protobuf dependencies
 #############################
 
@@ -112,13 +118,13 @@
 # Load Robolectric repository
 #############################
 
-ROBOLECTRIC_VERSION = "4.4"
+ROBOLECTRIC_VERSION = "4.11.1"
 
 http_archive(
     name = "robolectric",
-    sha256 = "d4f2eb078a51f4e534ebf5e18b6cd4646d05eae9b362ac40b93831bdf46112c7",
+    sha256 = "1ea1cfe67848decf959316e80dd69af2bbaa359ae2195efe1366cbdf3e968356",
     strip_prefix = "robolectric-bazel-%s" % ROBOLECTRIC_VERSION,
-    urls = ["https://github.com/robolectric/robolectric-bazel/archive/%s.tar.gz" % ROBOLECTRIC_VERSION],
+    urls = ["https://github.com/robolectric/robolectric-bazel/releases/download/%s/robolectric-bazel-%s.tar.gz" % (ROBOLECTRIC_VERSION, ROBOLECTRIC_VERSION)],
 )
 
 load("@robolectric//bazel:robolectric.bzl", "robolectric_repositories")
@@ -129,33 +135,34 @@
 # Load Kotlin repository
 #############################
 
-RULES_KOTLIN_TAG = "v1.8"
+RULES_KOTLIN_TAG = "1.9.6"
 
-RULES_KOTLIN_SHA = "01293740a16e474669aba5b5a1fe3d368de5832442f164e4fbfc566815a8bc3a"
+RULES_KOTLIN_SHA = "3b772976fec7bdcda1d84b9d39b176589424c047eb2175bed09aac630e50af43"
 
 http_archive(
     name = "io_bazel_rules_kotlin",
     sha256 = RULES_KOTLIN_SHA,
-    urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % RULES_KOTLIN_TAG],
+    urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v%s/rules_kotlin-v%s.tar.gz" % (RULES_KOTLIN_TAG, RULES_KOTLIN_TAG)],
 )
 
 load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version")
 
-KOTLIN_VERSION = "1.9.20"
+# TODO: update to Kotlin 2 once rules_kotlin support it.
+#   See https://github.com/bazelbuild/rules_kotlin/issues/1176
+KOTLINC_VERSION = "1.9.24"
 
 # Get from https://github.com/JetBrains/kotlin/releases/
-KOTLINC_RELEASE_SHA = "15a8a2825b74ccf6c44e04e97672db802d2df75ce2fbb63ef0539bf3ae5006f0"
+KOTLINC_RELEASE_SHA = "eb7b68e01029fa67bc8d060ee54c12018f2c60ddc438cf21db14517229aa693b"
 
 kotlin_repositories(
     compiler_release = kotlinc_version(
-        release = KOTLIN_VERSION,
+        release = KOTLINC_VERSION,
+        # Get from https://github.com/JetBrains/kotlin/releases/
         sha256 = KOTLINC_RELEASE_SHA,
     ),
 )
 
-load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
-
-kt_register_toolchains()
+register_toolchains("//:kotlin_toolchain")
 
 #############################
 # Load Maven dependencies
@@ -176,8 +183,20 @@
 
 ANDROID_LINT_VERSION = "30.1.0"
 
+ANT_VERSION = "1.9.6"
+
+ASM_VERSION = "9.6"
+
 AUTO_COMMON_VERSION = "1.2.1"
 
+BYTE_BUDDY_VERSION = "1.9.10"
+
+CHECKER_FRAMEWORK_VERSION = "2.5.3"
+
+ECLIPSE_SISU_VERSION = "0.3.0"
+
+ERROR_PRONE_VERSION = "2.14.0"
+
 # NOTE(bcorso): Even though we set the version here, our Guava version in
 #  processor code will use whatever version is built into JavaBuilder, which is
 #  tied to the version of Bazel we're using.
@@ -187,13 +206,11 @@
 
 INCAP_VERSION = "0.2"
 
-BYTE_BUDDY_VERSION = "1.9.10"
+KOTLIN_VERSION = "2.0.21"
 
-CHECKER_FRAMEWORK_VERSION = "2.5.3"
+KSP_VERSION = KOTLIN_VERSION + "-1.0.28"
 
-ERROR_PRONE_VERSION = "2.14.0"
-
-KSP_VERSION = KOTLIN_VERSION + "-1.0.14"
+MAVEN_VERSION = "3.3.3"
 
 maven_install(
     artifacts = [
@@ -233,6 +250,8 @@
         "com.google.code.findbugs:jsr305:3.0.1",
         "com.google.devtools.ksp:symbol-processing:%s" % KSP_VERSION,
         "com.google.devtools.ksp:symbol-processing-api:%s" % KSP_VERSION,
+        "com.google.devtools.ksp:symbol-processing-common-deps:%s" % KSP_VERSION,
+        "com.google.devtools.ksp:symbol-processing-aa-embeddable:%s" % KSP_VERSION,
         "com.google.errorprone:error_prone_annotation:%s" % ERROR_PRONE_VERSION,
         "com.google.errorprone:error_prone_annotations:%s" % ERROR_PRONE_VERSION,
         "com.google.errorprone:error_prone_check_api:%s" % ERROR_PRONE_VERSION,
@@ -253,6 +272,7 @@
         "io.grpc:grpc-protobuf:%s" % GRPC_VERSION,
         "jakarta.inject:jakarta.inject-api:2.0.1",
         "javax.annotation:javax.annotation-api:1.3.2",
+        "javax.enterprise:cdi-api:1.0",
         "javax.inject:javax.inject:1",
         "javax.inject:javax.inject-tck:1",
         "junit:junit:4.13",
@@ -260,20 +280,34 @@
         "net.bytebuddy:byte-buddy-agent:%s" % BYTE_BUDDY_VERSION,
         "net.ltgt.gradle.incap:incap:%s" % INCAP_VERSION,
         "net.ltgt.gradle.incap:incap-processor:%s" % INCAP_VERSION,
+        "org.apache.ant:ant:%s" % ANT_VERSION,
+        "org.apache.ant:ant-launcher:%s" % ANT_VERSION,
+        "org.apache.maven:maven-artifact:%s" % MAVEN_VERSION,
+        "org.apache.maven:maven-model:%s" % MAVEN_VERSION,
+        "org.apache.maven:maven-plugin-api:%s" % MAVEN_VERSION,
         "org.checkerframework:checker-compat-qual:%s" % CHECKER_FRAMEWORK_VERSION,
         "org.checkerframework:dataflow:%s" % CHECKER_FRAMEWORK_VERSION,
         "org.checkerframework:javacutil:%s" % CHECKER_FRAMEWORK_VERSION,
+        "org.codehaus.plexus:plexus-utils:3.0.20",
+        "org.codehaus.plexus:plexus-classworlds:2.5.2",
+        "org.codehaus.plexus:plexus-component-annotations:1.5.5",
+        "org.eclipse.sisu:org.eclipse.sisu.plexus:%s" % ECLIPSE_SISU_VERSION,
+        "org.eclipse.sisu:org.eclipse.sisu.inject:%s" % ECLIPSE_SISU_VERSION,
         "org.hamcrest:hamcrest-core:1.3",
         "org.jetbrains.kotlin:kotlin-annotation-processing-embeddable:%s" % KOTLIN_VERSION,
         "org.jetbrains.kotlin:kotlin-compiler-embeddable:%s" % KOTLIN_VERSION,
         "org.jetbrains.kotlin:kotlin-daemon-embeddable:%s" % KOTLIN_VERSION,
+        "org.jetbrains.kotlin:kotlin-metadata-jvm:%s" % KOTLIN_VERSION,
         "org.jetbrains.kotlin:kotlin-stdlib:%s" % KOTLIN_VERSION,
-        "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.2",
-        "org.jspecify:jspecify:0.3.0",
+        "org.jspecify:jspecify:1.0.0",
         "org.mockito:mockito-core:2.28.2",
+        "org.pantsbuild:jarjar:1.7.2",
         "org.objenesis:objenesis:1.0",
-        "org.robolectric:robolectric:4.4",
-        "org.robolectric:shadows-framework:4.4",  # For ActivityController
+        "org.ow2.asm:asm:%s" % ASM_VERSION,
+        "org.ow2.asm:asm-tree:%s" % ASM_VERSION,
+        "org.ow2.asm:asm-commons:%s" % ASM_VERSION,
+        "org.robolectric:robolectric:%s" % ROBOLECTRIC_VERSION,
+        "org.robolectric:shadows-framework:%s" % ROBOLECTRIC_VERSION,  # For ActivityController
     ],
     repositories = [
         "https://repo1.maven.org/maven2",
diff --git a/buildSrc/README.md b/buildSrc/README.md
new file mode 100644
index 0000000..7ebd532
--- /dev/null
+++ b/buildSrc/README.md
@@ -0,0 +1,3 @@
+### Dagger's Gradle build logic
+
+See https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources
\ No newline at end of file
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 0000000..66dc027
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,30 @@
+plugins {
+    `kotlin-dsl`
+}
+
+kotlin {
+    jvmToolchain {
+        languageVersion.set(libs.versions.jdk.map(JavaLanguageVersion::of))
+    }
+}
+
+dependencies {
+    implementation(gradleApi())
+    implementation(libs.kotlin.gradlePlugin)
+    implementation(libs.publishPlugin)
+}
+
+gradlePlugin {
+    plugins {
+        register("kotlinJvm") {
+            id = libs.plugins.dagger.kotlinJvm.get().pluginId
+            implementationClass = "dagger.gradle.build.KotlinJvmConventionPlugin"
+        }
+    }
+    plugins {
+      register("publish") {
+        id = libs.plugins.dagger.publish.get().pluginId
+        implementationClass = "dagger.gradle.build.PublishConventionPlugin"
+      }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 0000000..c4843c5
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
@@ -0,0 +1,18 @@
+pluginManagement {
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+dependencyResolutionManagement {
+    repositories {
+        google()
+        mavenCentral()
+    }
+    versionCatalogs {
+        create("libs") {
+            from(files("../gradle/libs.versions.toml"))
+        }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/dagger/gradle/build/KotlinJvmConventionPlugin.kt b/buildSrc/src/main/kotlin/dagger/gradle/build/KotlinJvmConventionPlugin.kt
new file mode 100644
index 0000000..e5dd52d
--- /dev/null
+++ b/buildSrc/src/main/kotlin/dagger/gradle/build/KotlinJvmConventionPlugin.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 The Dagger 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
+ *
+ * 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 dagger.gradle.build
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.gradle.jvm.toolchain.JavaLanguageVersion
+
+class KotlinJvmConventionPlugin : Plugin<Project> {
+
+    override fun apply(project: Project) {
+        project.pluginManager.apply(project.getPluginIdByName("kotlinJvm"))
+
+        project.plugins.withId(project.getPluginIdByName("kotlinJvm")) {
+            val kotlinProject = project.extensions.getByName("kotlin") as KotlinJvmProjectExtension
+            kotlinProject.explicitApi()
+            kotlinProject.jvmToolchain {
+                languageVersion.set(JavaLanguageVersion.of(project.getVersionByName("jdk")))
+            }
+            kotlinProject.compilerOptions.apply {
+                languageVersion.set(KotlinVersion.fromVersion(project.getVersionByName("kotlinTarget")))
+                apiVersion.set(KotlinVersion.fromVersion(project.getVersionByName("kotlinTarget")))
+                jvmTarget.set(JvmTarget.fromTarget(project.getVersionByName("jvmTarget")))
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/dagger/gradle/build/PublishConventionPlugin.kt b/buildSrc/src/main/kotlin/dagger/gradle/build/PublishConventionPlugin.kt
new file mode 100644
index 0000000..360ff71
--- /dev/null
+++ b/buildSrc/src/main/kotlin/dagger/gradle/build/PublishConventionPlugin.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2025 The Dagger 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
+ *
+ * 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 dagger.gradle.build
+
+import com.vanniktech.maven.publish.MavenPublishBaseExtension
+import com.vanniktech.maven.publish.SonatypeHost
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class PublishConventionPlugin : Plugin<Project> {
+    override fun apply(project: Project) {
+        project.pluginManager.apply(project.getPluginIdByName("publish"))
+
+        project.plugins.withId(project.getPluginIdByName("publish")) {
+            val publishExtension = project.extensions.getByName("mavenPublishing") as MavenPublishBaseExtension
+            publishExtension.apply {
+                coordinates(
+                    groupId = "com.google.dagger",
+                    artifactId = project.name,
+                    version = project.findProperty("PUBLISH_VERSION").toString()
+                )
+                publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
+                pom {
+                    name.set(project.name.asPomName())
+                    description.set("A fast dependency injector for Android and Java.")
+                    url.set("https://github.com/google/dagger")
+                    scm {
+                        url.set("https://github.com/google/dagger/")
+                        connection.set("scm:git:git://github.com/google/dagger.git")
+                    }
+                    issueManagement {
+                        system.set("GitHub Issues")
+                        url.set("https://github.com/google/dagger/issues")
+                    }
+                    licenses {
+                        license {
+                            name.set("The Apache Software License, Version 2.0")
+                            url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
+                        }
+                    }
+                    organization {
+                        name.set("Google, Inc.")
+                        url.set("https://www.google.com")
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Converts the Gradle project name to a more appropriate name for the POM file.
+     *
+     * For example: 'dagger-compiler' to 'Dagger Compiler'
+     */
+    private fun String.asPomName(): String {
+        val parts = split("-").map { first().uppercaseChar() + drop(1) }
+        return parts.joinToString(separator = " ")
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/dagger/gradle/build/ResourceCopyTask.kt b/buildSrc/src/main/kotlin/dagger/gradle/build/ResourceCopyTask.kt
new file mode 100644
index 0000000..06bb8e8
--- /dev/null
+++ b/buildSrc/src/main/kotlin/dagger/gradle/build/ResourceCopyTask.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 The Dagger 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
+ *
+ * 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 dagger.gradle.build
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.RegularFile
+import org.gradle.api.provider.ListProperty
+import org.gradle.api.provider.MapProperty
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity
+import org.gradle.api.tasks.TaskAction
+import org.gradle.work.DisableCachingByDefault
+
+/**
+ * A task for copying JAR resources files located in the repository structure into a generated resource source set
+ * that matches the JAR's resources structure. This is necessary due to the repository's structure not being the
+ * standard Gradle source set structure.
+ */
+@DisableCachingByDefault(because = "Not worth caching")
+abstract class ResourceCopyTask : DefaultTask() {
+
+    /**
+     * Specifications of resource files to copy and their destination directory within the JAR.
+     */
+    @get:Input
+    abstract val resourceSpecs: MapProperty<String, String>
+
+    @get:InputFiles
+    @get:PathSensitive(PathSensitivity.RELATIVE)
+    abstract val inputFiles: ListProperty<RegularFile>
+
+    @get:OutputDirectory
+    abstract val outputDirectory: DirectoryProperty
+
+    @TaskAction
+    fun execute() {
+        val specMap = resourceSpecs.get()
+        inputFiles.get().forEach { resourceFile ->
+            val inputFile = resourceFile.asFile
+            check(inputFile.exists()) {
+                "Resource file does not exist: $inputFile"
+            }
+            check(inputFile.isFile) {
+                "Resource file must be a file not a directory: $inputFile"
+            }
+            val jarOutputDir = specMap.getValue(inputFile.path)
+            val outputFile = outputDirectory.get().dir(jarOutputDir).file(inputFile.name).asFile
+            inputFile.copyTo(outputFile, overwrite = true)
+        }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/dagger/gradle/build/SourceSetConfiguration.kt b/buildSrc/src/main/kotlin/dagger/gradle/build/SourceSetConfiguration.kt
new file mode 100644
index 0000000..06975cc
--- /dev/null
+++ b/buildSrc/src/main/kotlin/dagger/gradle/build/SourceSetConfiguration.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.gradle.build
+
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.api.tasks.TaskProvider
+import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
+import java.nio.file.Path
+import kotlin.io.path.Path
+import kotlin.io.path.isDirectory
+
+private typealias JavaSourceSet = org.gradle.api.tasks.SourceSet
+
+@DslMarker
+annotation class DaggerGradleDsl
+
+@DaggerGradleDsl
+class DaggerSourceSet(
+    private val project: Project,
+    private val kotlinSourceSets: NamedDomainObjectContainer<KotlinSourceSet>,
+    private val javaSourceSets: NamedDomainObjectContainer<JavaSourceSet>,
+) {
+    private val resourceCopyTask: TaskProvider<ResourceCopyTask> =
+        project.tasks.register("copyResources", ResourceCopyTask::class.java) {
+            outputDirectory.set(project.layout.buildDirectory.dir("generated/resources"))
+        }
+
+    init {
+        listOf(resourceCopyTask.map { it.outputDirectory }).let {
+            kotlinSourceSets.named("main").configure { resources.setSrcDirs(it) }
+            javaSourceSets.named("main").configure { resources.setSrcDirs(it) }
+        }
+    }
+
+    /**
+     * The main source set whose based path is `<root>/java`
+     */
+    val main: SourceSet = object : SourceSet {
+        override fun setPackages(packages: List<String>) {
+            val packagePaths = packages.map { Path(it) }
+            kotlinSourceSets.named("main").configure {
+                kotlin.includePackages("${project.rootDir}/java", packagePaths)
+            }
+            javaSourceSets.named("main").configure {
+                java.includePackages("${project.rootDir}/java", packagePaths)
+            }
+        }
+
+        override fun setResources(resources: Map<String, String>) {
+            resourceCopyTask.configure {
+                val baseDir = project.rootProject.layout.projectDirectory.dir("java")
+                resources.forEach { (resourceFilePath, jarDirectoryPath) ->
+                    val resource = baseDir.file(resourceFilePath)
+                    resourceSpecs.put(resource.asFile.path, jarDirectoryPath)
+                    inputFiles.add(resource)
+                }
+            }
+        }
+    }
+
+    /**
+     * The main source set whose based path is `<root>/javatests`
+     */
+    val test: SourceSet = object : SourceSet {
+        override fun setPackages(packages: List<String>) {
+            val packagePaths = packages.map { Path(it) }
+            kotlinSourceSets.named("test").configure {
+                kotlin.includePackages("${project.rootDir}/javatests", packagePaths)
+            }
+            javaSourceSets.named("test").configure {
+                java.includePackages("${project.rootDir}/javatests", packagePaths)
+            }
+        }
+
+        override fun setResources(resources: Map<String, String>) {
+            throw UnsupportedOperationException(
+                "Resources are only configurable for the 'main' source set."
+            )
+        }
+    }
+
+    interface SourceSet {
+        /**
+         * Sets the list of source packages that are part of the project's source set.
+         *
+         * Only sources directly in those packages are included and not in its subpackages.
+         *
+         * Example usage:
+         * ```
+         * daggerSources {
+         *     main.setPackages(
+         *         listOf(
+         *             "dagger",
+         *             "dagger/assisted",
+         *             "dagger/internal",
+         *             "dagger/multibindings",
+         *         )
+         *     )
+         * }
+         * ```
+         * @see daggerSources
+         */
+        fun setPackages(packages: List<String>)
+
+        /**
+         * Sets the resource file paths and their corresponding artifact location.
+         *
+         * Example usage:
+         * ```
+         * daggerSources {
+         *     main.setResources(
+         *         mapOf("dagger/r8.pro" to "META-INF/com.android.tools/r8/")
+         *     )
+         * }
+         * ```
+         * @see daggerSources
+         */
+        fun setResources(resources: Map<String, String>)
+    }
+}
+
+/**
+ * Configure project's source set based on Dagger's project structure.
+ *
+ * Specifically it will include sources in the packages specified by
+ * [DaggerSourceSet.SourceSet.setPackages] and resources as specified by
+ * [DaggerSourceSet.SourceSet.setResources].
+ */
+fun Project.daggerSources(block: DaggerSourceSet.() -> Unit) {
+    val kotlinExtension = extensions.findByType(KotlinProjectExtension::class.java)
+        ?: error("The daggerSources() configuration must be applied to a Kotlin (JVM) project.")
+    val javaExtension = extensions.findByType(JavaPluginExtension::class.java)
+        ?: error("The daggerSources() configuration must be applied to a Kotlin (JVM) project.")
+    val daggerSources = DaggerSourceSet(this, kotlinExtension.sourceSets, javaExtension.sourceSets)
+    block.invoke(daggerSources)
+}
+
+/**
+ * Includes sources from the given [packages] into this source set.
+ *
+ * Only sources within the package directory are included and not its sub-packages.
+ */
+private fun SourceDirectorySet.includePackages(
+    basePath: String,
+    packages: Iterable<Path>,
+) {
+    val packagesDirectories = packages.flatMap { it.expandParts() }.toSet()
+    setSrcDirs(listOf(basePath)).include {
+        val path = Path(it.path)
+        if (Path(basePath).resolve(path).isDirectory()) {
+            path in packagesDirectories
+        } else {
+            path.parent in packages
+        }
+    }
+}
+
+/**
+ * Expands a [Path] to includes it parents.
+ *
+ * i.e. for `"foo/bar"` it will expand to `setOf("foo", foo/bar")`
+ */
+private fun Path.expandParts(): Set<Path> {
+    return buildSet {
+        var path: Path? = this@expandParts
+        while (path != null) {
+            add(path)
+            path = path.parent
+        }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/dagger/gradle/build/VersionCatalogs.kt b/buildSrc/src/main/kotlin/dagger/gradle/build/VersionCatalogs.kt
new file mode 100644
index 0000000..c9f034b
--- /dev/null
+++ b/buildSrc/src/main/kotlin/dagger/gradle/build/VersionCatalogs.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 The Dagger 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
+ *
+ * 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 dagger.gradle.build
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.artifacts.VersionCatalogsExtension
+
+internal val Project.versionCatalog: VersionCatalog
+    get() = project.extensions.getByType(VersionCatalogsExtension::class.java).find("libs").get()
+
+internal fun Project.getVersionByName(name: String): String {
+    val version = versionCatalog.findVersion(name)
+    return if (version.isPresent) {
+        version.get().requiredVersion
+    } else {
+        error("Could not find a version for `$name`")
+    }
+}
+
+internal fun Project.getPluginIdByName(name: String): String {
+    val plugin = versionCatalog.findPlugin(name)
+    return if (plugin.isPresent) {
+        plugin.get().map { it.pluginId }.get()
+    } else {
+        error("Could not find plugin id for `$name`")
+    }
+}
\ No newline at end of file
diff --git a/build_defs.bzl b/build_defs.bzl
index 70afaf0..3dd0647 100644
--- a/build_defs.bzl
+++ b/build_defs.bzl
@@ -18,8 +18,6 @@
 
 DOCLINT_REFERENCES = ["-Xdoclint:reference"]
 
-JAVA_RELEASE_MIN = [
-    "-source 7 -target 7",
-]
+JAVA_RELEASE_MIN = ["-source 8 -target 8"]
 
 POM_VERSION = "${project.version}"
diff --git a/examples/bazel/.bazelversion b/examples/bazel/.bazelversion
new file mode 100644
index 0000000..c0be8a7
--- /dev/null
+++ b/examples/bazel/.bazelversion
@@ -0,0 +1 @@
+6.4.0
\ No newline at end of file
diff --git a/examples/bazel/WORKSPACE b/examples/bazel/WORKSPACE
index 3ad378c..7c9a8db 100644
--- a/examples/bazel/WORKSPACE
+++ b/examples/bazel/WORKSPACE
@@ -41,8 +41,8 @@
 
 android_sdk_repository(
     name = "androidsdk",
-    api_level = 32,
-    build_tools_version = "32.0.0",
+    api_level = 34,
+    build_tools_version = "34.0.0",
 )
 
 #############################
@@ -51,10 +51,13 @@
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
+ROBOLECTRIC_VERSION = "4.11.1"
+
 http_archive(
     name = "robolectric",
-    strip_prefix = "robolectric-bazel-4.1",
-    urls = ["https://github.com/robolectric/robolectric-bazel/archive/4.1.tar.gz"],
+    sha256 = "1ea1cfe67848decf959316e80dd69af2bbaa359ae2195efe1366cbdf3e968356",
+    strip_prefix = "robolectric-bazel-%s" % ROBOLECTRIC_VERSION,
+    urls = ["https://github.com/robolectric/robolectric-bazel/releases/download/%s/robolectric-bazel-%s.tar.gz" % (ROBOLECTRIC_VERSION, ROBOLECTRIC_VERSION)],
 )
 
 load("@robolectric//bazel:robolectric.bzl", "robolectric_repositories")
@@ -84,8 +87,8 @@
         "androidx.test:runner:1.1.1",
         "com.google.truth:truth:1.0.1",
         "junit:junit:4.13",
-        "org.robolectric:robolectric:4.1",
-        "org.robolectric:annotations:4.1",
+        "org.robolectric:robolectric:%s" % ROBOLECTRIC_VERSION,
+        "org.robolectric:annotations:%s" % ROBOLECTRIC_VERSION,
     ],
     repositories = DAGGER_REPOSITORIES + HILT_ANDROID_REPOSITORIES,
 )
diff --git a/gradle-projects/README.md b/gradle-projects/README.md
new file mode 100644
index 0000000..2024ba6
--- /dev/null
+++ b/gradle-projects/README.md
@@ -0,0 +1,6 @@
+### Dagger's Gradle projects directories
+
+Each directory is a Gradle sub-project that maps to an artifact and whose sources are part of the
+Bazel project structure. At the root of the repository is the parent project that includes the
+ones in these directory.
+
diff --git a/gradle-projects/dagger-runtime/api/dagger.api b/gradle-projects/dagger-runtime/api/dagger.api
new file mode 100644
index 0000000..36ed2a3
--- /dev/null
+++ b/gradle-projects/dagger-runtime/api/dagger.api
@@ -0,0 +1,282 @@
+public abstract interface annotation class dagger/Binds : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/BindsInstance : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/BindsOptionalOf : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/Component : java/lang/annotation/Annotation {
+	public abstract fun dependencies ()[Ljava/lang/Class;
+	public abstract fun modules ()[Ljava/lang/Class;
+}
+
+public abstract interface annotation class dagger/Component$Builder : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/Component$Factory : java/lang/annotation/Annotation {
+}
+
+public abstract interface class dagger/Lazy {
+	public abstract fun get ()Ljava/lang/Object;
+}
+
+public abstract interface annotation class dagger/MapKey : java/lang/annotation/Annotation {
+	public abstract fun unwrapValue ()Z
+}
+
+public abstract interface class dagger/MembersInjector {
+	public abstract fun injectMembers (Ljava/lang/Object;)V
+}
+
+public abstract interface annotation class dagger/Module : java/lang/annotation/Annotation {
+	public abstract fun includes ()[Ljava/lang/Class;
+	public abstract fun subcomponents ()[Ljava/lang/Class;
+}
+
+public abstract interface annotation class dagger/Provides : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/Reusable : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/Subcomponent : java/lang/annotation/Annotation {
+	public abstract fun modules ()[Ljava/lang/Class;
+}
+
+public abstract interface annotation class dagger/Subcomponent$Builder : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/Subcomponent$Factory : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/assisted/Assisted : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/String;
+}
+
+public abstract interface annotation class dagger/assisted/AssistedFactory : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/assisted/AssistedInject : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/internal/Beta : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/internal/ComponentDefinitionType : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/Class;
+}
+
+public final class dagger/internal/DaggerCollections {
+	public static fun hasDuplicates (Ljava/util/List;)Z
+	public static fun newLinkedHashMapWithExpectedSize (I)Ljava/util/LinkedHashMap;
+	public static fun presizedList (I)Ljava/util/List;
+}
+
+public abstract interface annotation class dagger/internal/DaggerGenerated : java/lang/annotation/Annotation {
+}
+
+public final class dagger/internal/DelegateFactory : dagger/internal/Factory {
+	public fun <init> ()V
+	public fun get ()Ljava/lang/Object;
+	public static fun setDelegate (Ldagger/internal/Provider;Ldagger/internal/Provider;)V
+	public static fun setDelegate (Ljavax/inject/Provider;Ljavax/inject/Provider;)V
+	public fun setDelegatedProvider (Ldagger/internal/Provider;)V
+	public fun setDelegatedProvider (Ljavax/inject/Provider;)V
+}
+
+public final class dagger/internal/DoubleCheck : dagger/Lazy, dagger/internal/Provider {
+	public fun get ()Ljava/lang/Object;
+	public static fun lazy (Ldagger/internal/Provider;)Ldagger/Lazy;
+	public static fun lazy (Ljavax/inject/Provider;)Ldagger/Lazy;
+	public static fun provider (Ldagger/internal/Provider;)Ldagger/internal/Provider;
+	public static fun provider (Ljavax/inject/Provider;)Ljavax/inject/Provider;
+}
+
+public abstract interface class dagger/internal/Factory : dagger/internal/Provider {
+}
+
+public abstract interface annotation class dagger/internal/GwtIncompatible : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/internal/IdentifierNameString : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/internal/InjectedFieldSignature : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/String;
+}
+
+public final class dagger/internal/InstanceFactory : dagger/Lazy, dagger/internal/Factory {
+	public static fun create (Ljava/lang/Object;)Ldagger/internal/Factory;
+	public static fun createNullable (Ljava/lang/Object;)Ldagger/internal/Factory;
+	public fun get ()Ljava/lang/Object;
+}
+
+public abstract interface annotation class dagger/internal/KeepFieldType : java/lang/annotation/Annotation {
+}
+
+public final class dagger/internal/LazyClassKeyMap : java/util/Map {
+	public fun clear ()V
+	public fun containsKey (Ljava/lang/Object;)Z
+	public fun containsValue (Ljava/lang/Object;)Z
+	public fun entrySet ()Ljava/util/Set;
+	public fun get (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun isEmpty ()Z
+	public fun keySet ()Ljava/util/Set;
+	public static fun of (Ljava/util/Map;)Ljava/util/Map;
+	public fun put (Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun putAll (Ljava/util/Map;)V
+	public fun remove (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun size ()I
+	public fun values ()Ljava/util/Collection;
+}
+
+public class dagger/internal/LazyClassKeyMap$MapFactory : dagger/internal/Factory {
+	public synthetic fun get ()Ljava/lang/Object;
+	public fun get ()Ljava/util/Map;
+	public static fun of (Ldagger/internal/Factory;)Ldagger/internal/LazyClassKeyMap$MapFactory;
+}
+
+public class dagger/internal/LazyClassKeyMap$MapProviderFactory : dagger/internal/Factory {
+	public synthetic fun get ()Ljava/lang/Object;
+	public fun get ()Ljava/util/Map;
+	public static fun of (Ldagger/internal/Factory;)Ldagger/internal/LazyClassKeyMap$MapProviderFactory;
+}
+
+public final class dagger/internal/MapBuilder {
+	public fun build ()Ljava/util/Map;
+	public static fun newMapBuilder (I)Ldagger/internal/MapBuilder;
+	public fun put (Ljava/lang/Object;Ljava/lang/Object;)Ldagger/internal/MapBuilder;
+	public fun putAll (Ljava/util/Map;)Ldagger/internal/MapBuilder;
+}
+
+public final class dagger/internal/MapFactory {
+	public static fun builder (I)Ldagger/internal/MapFactory$Builder;
+	public static fun emptyMapProvider ()Ldagger/internal/Provider;
+	public synthetic fun get ()Ljava/lang/Object;
+	public fun get ()Ljava/util/Map;
+}
+
+public final class dagger/internal/MapFactory$Builder {
+	public fun build ()Ldagger/internal/MapFactory;
+	public synthetic fun put (Ljava/lang/Object;Ldagger/internal/Provider;)Ldagger/internal/AbstractMapFactory$Builder;
+	public fun put (Ljava/lang/Object;Ldagger/internal/Provider;)Ldagger/internal/MapFactory$Builder;
+	public fun put (Ljava/lang/Object;Ljavax/inject/Provider;)Ldagger/internal/MapFactory$Builder;
+	public synthetic fun putAll (Ldagger/internal/Provider;)Ldagger/internal/AbstractMapFactory$Builder;
+	public fun putAll (Ldagger/internal/Provider;)Ldagger/internal/MapFactory$Builder;
+	public fun putAll (Ljavax/inject/Provider;)Ldagger/internal/MapFactory$Builder;
+}
+
+public final class dagger/internal/MapProviderFactory : dagger/Lazy {
+	public static fun builder (I)Ldagger/internal/MapProviderFactory$Builder;
+	public synthetic fun get ()Ljava/lang/Object;
+	public fun get ()Ljava/util/Map;
+}
+
+public final class dagger/internal/MapProviderFactory$Builder {
+	public fun build ()Ldagger/internal/MapProviderFactory;
+	public synthetic fun put (Ljava/lang/Object;Ldagger/internal/Provider;)Ldagger/internal/AbstractMapFactory$Builder;
+	public fun put (Ljava/lang/Object;Ldagger/internal/Provider;)Ldagger/internal/MapProviderFactory$Builder;
+	public fun put (Ljava/lang/Object;Ljavax/inject/Provider;)Ldagger/internal/MapProviderFactory$Builder;
+	public synthetic fun putAll (Ldagger/internal/Provider;)Ldagger/internal/AbstractMapFactory$Builder;
+	public fun putAll (Ldagger/internal/Provider;)Ldagger/internal/MapProviderFactory$Builder;
+	public fun putAll (Ljavax/inject/Provider;)Ldagger/internal/MapProviderFactory$Builder;
+}
+
+public final class dagger/internal/MembersInjectors {
+	public static fun noOp ()Ldagger/MembersInjector;
+}
+
+public final class dagger/internal/Preconditions {
+	public static fun checkBuilderRequirement (Ljava/lang/Object;Ljava/lang/Class;)V
+	public static fun checkNotNull (Ljava/lang/Object;)Ljava/lang/Object;
+	public static fun checkNotNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
+	public static fun checkNotNull (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
+	public static fun checkNotNullFromComponent (Ljava/lang/Object;)Ljava/lang/Object;
+	public static fun checkNotNullFromProvides (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public abstract interface class dagger/internal/Provider : jakarta/inject/Provider, javax/inject/Provider {
+}
+
+public final class dagger/internal/ProviderOfLazy : dagger/internal/Provider {
+	public static fun create (Ldagger/internal/Provider;)Ldagger/internal/Provider;
+	public static fun create (Ljavax/inject/Provider;)Ldagger/internal/Provider;
+	public fun get ()Ldagger/Lazy;
+	public synthetic fun get ()Ljava/lang/Object;
+}
+
+public final class dagger/internal/Providers {
+	public static fun asDaggerProvider (Ljavax/inject/Provider;)Ldagger/internal/Provider;
+}
+
+public abstract interface annotation class dagger/internal/QualifierMetadata : java/lang/annotation/Annotation {
+	public abstract fun value ()[Ljava/lang/String;
+}
+
+public abstract interface annotation class dagger/internal/ScopeMetadata : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/String;
+}
+
+public final class dagger/internal/SetBuilder {
+	public fun add (Ljava/lang/Object;)Ldagger/internal/SetBuilder;
+	public fun addAll (Ljava/util/Collection;)Ldagger/internal/SetBuilder;
+	public fun build ()Ljava/util/Set;
+	public static fun newSetBuilder (I)Ldagger/internal/SetBuilder;
+}
+
+public final class dagger/internal/SetFactory : dagger/internal/Factory {
+	public static fun builder (II)Ldagger/internal/SetFactory$Builder;
+	public static fun empty ()Ldagger/internal/Factory;
+	public synthetic fun get ()Ljava/lang/Object;
+	public fun get ()Ljava/util/Set;
+}
+
+public final class dagger/internal/SetFactory$Builder {
+	public fun addCollectionProvider (Ldagger/internal/Provider;)Ldagger/internal/SetFactory$Builder;
+	public fun addCollectionProvider (Ljavax/inject/Provider;)Ldagger/internal/SetFactory$Builder;
+	public fun addProvider (Ldagger/internal/Provider;)Ldagger/internal/SetFactory$Builder;
+	public fun addProvider (Ljavax/inject/Provider;)Ldagger/internal/SetFactory$Builder;
+	public fun build ()Ldagger/internal/SetFactory;
+}
+
+public final class dagger/internal/SingleCheck : dagger/internal/Provider {
+	public fun get ()Ljava/lang/Object;
+	public static fun provider (Ldagger/internal/Provider;)Ldagger/internal/Provider;
+	public static fun provider (Ljavax/inject/Provider;)Ljavax/inject/Provider;
+}
+
+public abstract interface annotation class dagger/multibindings/ClassKey : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/Class;
+}
+
+public abstract interface annotation class dagger/multibindings/ElementsIntoSet : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/multibindings/IntKey : java/lang/annotation/Annotation {
+	public abstract fun value ()I
+}
+
+public abstract interface annotation class dagger/multibindings/IntoMap : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/multibindings/IntoSet : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/multibindings/LazyClassKey : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/Class;
+}
+
+public abstract interface annotation class dagger/multibindings/LongKey : java/lang/annotation/Annotation {
+	public abstract fun value ()J
+}
+
+public abstract interface annotation class dagger/multibindings/Multibinds : java/lang/annotation/Annotation {
+}
+
+public abstract interface annotation class dagger/multibindings/StringKey : java/lang/annotation/Annotation {
+	public abstract fun value ()Ljava/lang/String;
+}
+
diff --git a/gradle-projects/dagger-runtime/build.gradle.kts b/gradle-projects/dagger-runtime/build.gradle.kts
new file mode 100644
index 0000000..fa1bf61
--- /dev/null
+++ b/gradle-projects/dagger-runtime/build.gradle.kts
@@ -0,0 +1,40 @@
+import dagger.gradle.build.daggerSources
+
+plugins {
+    alias(libs.plugins.dagger.kotlinJvm)
+    alias(libs.plugins.dagger.publish)
+    alias(libs.plugins.binaryCompatibilityValidator)
+}
+
+daggerSources {
+    main.setPackages(
+        listOf(
+            "dagger",
+            "dagger/assisted",
+            "dagger/internal",
+            "dagger/multibindings",
+        )
+    )
+    main.setResources(
+        mapOf(
+            "dagger/proguard.pro" to "META-INF/com.android.tools/proguard",
+            "dagger/r8.pro" to "META-INF/com.android.tools/r8"
+        )
+    )
+    test.setPackages(
+        listOf(
+            "dagger",
+            "dagger/internal",
+        )
+    )
+}
+
+dependencies {
+    api(libs.javax.inject)
+    api(libs.jakarta.inject)
+    api(libs.jspecify)
+
+    testImplementation(libs.junit)
+    testImplementation(libs.truth)
+    testImplementation(libs.guava.jre)
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..9b5bb06
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,25 @@
+# Project-wide Gradle settings.
+# IDE (e.g. IntelliJ or Android Studio) users:
+# Gradle settings configured through the IDE *will override* any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx4g -Xms4g -Dfile.encoding=UTF-8
+kotlin.daemon.jvmargs=-Xmx4g -Xms4g -Dfile.encoding=UTF-8
+
+# Enable caching between builds.
+org.gradle.caching=true
+
+# Enable configuration caching between builds.
+org.gradle.configuration-cache=true
+
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+
+# Don't include the stdlib as a dependency by default
+kotlin.stdlib.default.dependency=false
+
+# Publish version
+# TODO(danysantiago): Find a configurable location for the publishing version.
+PUBLISH_VERSION=LOCAL-SNAPSHOT
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..57cd6a0
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,27 @@
+[versions]
+guava = "33.0.0-jre"
+jdk = "18"
+junit = "4.13"
+jvmTarget = "1.8"
+kotlin = "2.0.21"
+kotlinTarget = "1.9"
+publish = "0.30.0"
+truth = "1.4.0"
+
+[libraries]
+guava-jre = { module = "com.google.guava:guava", version.ref = "guava" }
+jakarta-inject = { module = "jakarta.inject:jakarta.inject-api", version = "2.0.1" }
+javax-inject = { module = "javax.inject:javax.inject", version = "1" }
+jspecify = { module = "org.jspecify:jspecify", version = "1.0.0" }
+junit = { module = "junit:junit", version.ref = "junit" }
+kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
+kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
+publishPlugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "publish" }
+truth = { module = "com.google.truth:truth", version.ref = "truth" }
+
+[plugins]
+binaryCompatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.17.0" }
+dagger-kotlinJvm = { id = "dagger.gradle.build.jvm" }
+dagger-publish = { id = "dagger.gradle.build.publish" }
+kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
+publish = { id = "com.vanniktech.maven.publish", version.ref = "publish" }
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..a4b76b9
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..94113f2
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..f5feea6
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+#   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/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# 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
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+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
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        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
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# 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.
+
+# 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
+
+
+# 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"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+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..9d21a21
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,94 @@
+@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
+@rem SPDX-License-Identifier: Apache-2.0
+@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=.
+@rem This is normally unused
+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. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+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/gwt/BUILD b/gwt/BUILD
index 5aa9110..59cd4a5 100644
--- a/gwt/BUILD
+++ b/gwt/BUILD
@@ -16,13 +16,14 @@
 #   GWT-specific files for Dagger
 
 load("@rules_java//java:defs.bzl", "java_library")
-load("//tools:maven.bzl", "pom_file")
-load("//:build_defs.bzl", "POM_VERSION")
+load("//:build_defs.bzl", "JAVA_RELEASE_MIN", "POM_VERSION")
+load("//tools/maven:maven.bzl", "dagger_pom_file")
 
 package(default_visibility = ["//:src"])
 
 java_library(
     name = "gwt",
+    javacopts = JAVA_RELEASE_MIN,
     resource_strip_prefix = "gwt/",
     resources = glob(["**/*.gwt.xml"]),
     tags = ["maven_coordinates=com.google.dagger:dagger-gwt:" + POM_VERSION],
@@ -36,12 +37,14 @@
     name = "manual_deps",
     tags = [
         "maven_coordinates=com.google.dagger:dagger:%s:jar:sources" % POM_VERSION,
+        "maven_coordinates=jakarta.inject:jakarta.inject-api:2.0.1:jar:sources",
         "maven_coordinates=javax.inject:javax.inject:1:jar:sources",
+        "maven_coordinates=org.jspecify:jspecify:1.0.0:jar:sources",
     ],
     visibility = ["//visibility:private"],
 )
 
-pom_file(
+dagger_pom_file(
     name = "pom",
     artifact_id = "dagger-gwt",
     artifact_name = "Dagger GWT",
diff --git a/gwt/dagger/Dagger.gwt.xml b/gwt/dagger/Dagger.gwt.xml
index ad106fd..4298a32 100644
--- a/gwt/dagger/Dagger.gwt.xml
+++ b/gwt/dagger/Dagger.gwt.xml
@@ -15,6 +15,7 @@
 -->
 <module>
   <inherits name="javax.inject.Inject" />
-
+  <inherits name="jakarta.inject.Inject" />
+  <inherits name="org.jspecify.Jspecify" />
   <source path=""/>
 </module>
diff --git a/gwt/jakarta/inject/Inject.gwt.xml b/gwt/jakarta/inject/Inject.gwt.xml
new file mode 100644
index 0000000..cf56dfb
--- /dev/null
+++ b/gwt/jakarta/inject/Inject.gwt.xml
@@ -0,0 +1,18 @@
+<!--
+ Copyright (C) 2024 The Dagger 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
+
+       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.
+-->
+<module>
+  <source path=""/>
+</module>
\ No newline at end of file
diff --git a/gwt/org/jspecify/Jspecify.gwt.xml b/gwt/org/jspecify/Jspecify.gwt.xml
new file mode 100644
index 0000000..cf56dfb
--- /dev/null
+++ b/gwt/org/jspecify/Jspecify.gwt.xml
@@ -0,0 +1,18 @@
+<!--
+ Copyright (C) 2024 The Dagger 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
+
+       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.
+-->
+<module>
+  <source path=""/>
+</module>
\ No newline at end of file
diff --git a/java/dagger/BUILD b/java/dagger/BUILD
index 9183408..dc67ced 100644
--- a/java/dagger/BUILD
+++ b/java/dagger/BUILD
@@ -22,7 +22,7 @@
     "JAVA_RELEASE_MIN",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -33,7 +33,9 @@
     tags = ["maven_coordinates=com.google.dagger:dagger:" + POM_VERSION],
     exports = ["//third_party/java/jsr330_inject"],
     deps = [
+        "//third_party/java/jspecify_annotations",
         "//third_party/java/jsr330_inject",
+        "@maven//:jakarta_inject_jakarta_inject_api",
     ],
 )
 
@@ -43,6 +45,8 @@
     artifact_name = "Dagger",
     artifact_target = ":core",
     artifact_target_maven_deps = [
+        "org.jspecify:jspecify",
+        "jakarta.inject:jakarta.inject-api",
         "javax.inject:javax.inject",
     ],
     javadoc_root_packages = ["dagger"],
diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD
index 686e6ae..fe2183b 100644
--- a/java/dagger/android/BUILD
+++ b/java/dagger/android/BUILD
@@ -17,13 +17,15 @@
 
 load(
     "//:build_defs.bzl",
+    "DOCLINT_HTML_AND_SYNTAX",
+    "JAVA_RELEASE_MIN",
     "POM_VERSION",
 )
 load("//tools:dejetify.bzl", "dejetified_library")
 load(
-    "//tools:maven.bzl",
+    "//tools/maven:maven.bzl",
+    "dagger_pom_file",
     "gen_maven_artifact",
-    "pom_file",
 )
 
 package(default_visibility = ["//:src"])
@@ -43,6 +45,7 @@
 android_library(
     name = "android",
     srcs = SRCS,
+    javacopts = JAVA_RELEASE_MIN + DOCLINT_HTML_AND_SYNTAX,
     plugins = [
         "//java/dagger/android/internal/proguard:plugin",
     ],
@@ -68,7 +71,7 @@
         "com.google.dagger:dagger",
         "com.google.dagger:dagger-lint-aar",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_root_packages = [
         "dagger.android",
     ],
@@ -94,7 +97,7 @@
     ],
 )
 
-pom_file(
+dagger_pom_file(
     name = "legacy-pom",
     artifact_id = "dagger-android-legacy",
     artifact_name = "Dagger Android Legacy",
diff --git a/java/dagger/android/processor/BUILD b/java/dagger/android/processor/BUILD
index f70c091..16b662e 100644
--- a/java/dagger/android/processor/BUILD
+++ b/java/dagger/android/processor/BUILD
@@ -22,7 +22,7 @@
     "DOCLINT_REFERENCES",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/android/support/BUILD b/java/dagger/android/support/BUILD
index 2f4c407..aa01899 100644
--- a/java/dagger/android/support/BUILD
+++ b/java/dagger/android/support/BUILD
@@ -17,13 +17,15 @@
 
 load(
     "//:build_defs.bzl",
+    "DOCLINT_HTML_AND_SYNTAX",
+    "JAVA_RELEASE_MIN",
     "POM_VERSION",
 )
 load("//tools:dejetify.bzl", "dejetified_library")
 load(
-    "//tools:maven.bzl",
+    "//tools/maven:maven.bzl",
+    "dagger_pom_file",
     "gen_maven_artifact",
-    "pom_file",
 )
 
 package(default_visibility = ["//:src"])
@@ -36,6 +38,7 @@
 android_library(
     name = "support",
     srcs = glob(["*.java"]),
+    javacopts = JAVA_RELEASE_MIN + DOCLINT_HTML_AND_SYNTAX,
     tags = ["maven_coordinates=com.google.dagger:dagger-android-support:" + POM_VERSION],
     deps = [
         "//:dagger_with_compiler",
@@ -67,7 +70,7 @@
         "com.google.dagger:dagger",
         "com.google.dagger:dagger-android",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_root_packages = [
         "dagger.android.support",
     ],
@@ -95,7 +98,7 @@
     ],
 )
 
-pom_file(
+dagger_pom_file(
     name = "legacy-pom",
     artifact_id = "dagger-android-support-legacy",
     artifact_name = "Dagger Android Legacy Support",
diff --git a/java/dagger/grpc/server/BUILD b/java/dagger/grpc/server/BUILD
index 8aa82be..49d23b0 100644
--- a/java/dagger/grpc/server/BUILD
+++ b/java/dagger/grpc/server/BUILD
@@ -5,10 +5,11 @@
     "//:build_defs.bzl",
     "DOCLINT_HTML_AND_SYNTAX",
     "DOCLINT_REFERENCES",
+    "JAVA_RELEASE_MIN",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+load("//tools/javadoc:javadoc.bzl", "javadoc_library")
+load("//tools/maven:maven.bzl", "dagger_pom_file")
 
 package(default_visibility = ["//:src"])
 
@@ -21,7 +22,7 @@
 java_library(
     name = "annotations",
     srcs = ANNOTATIONS_SRCS,
-    javacopts = DOCLINT_HTML_AND_SYNTAX,
+    javacopts = DOCLINT_HTML_AND_SYNTAX + JAVA_RELEASE_MIN,
     tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server-annotations:" + POM_VERSION],
     deps = [
         "//third_party/java/jsr330_inject",
@@ -36,7 +37,7 @@
         exclude = ANNOTATIONS_SRCS,
     ),
     exported_plugins = ["//java/dagger/grpc/server/processor:plugin"],
-    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES + JAVA_RELEASE_MIN,
     tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server:" + POM_VERSION],
     exports = [":annotations"],
     deps = [
@@ -53,14 +54,14 @@
     ],
 )
 
-pom_file(
+dagger_pom_file(
     name = "annotations-pom",
     artifact_id = "dagger-grpc-server-annotations",
     artifact_name = "Dagger gRPC Server Annotations",
     targets = [":annotations"],
 )
 
-pom_file(
+dagger_pom_file(
     name = "server-pom",
     artifact_id = "dagger-grpc-server",
     artifact_name = "Dagger gRPC Server",
diff --git a/java/dagger/grpc/server/processor/BUILD b/java/dagger/grpc/server/processor/BUILD
index ed28836..79a2cfb 100644
--- a/java/dagger/grpc/server/processor/BUILD
+++ b/java/dagger/grpc/server/processor/BUILD
@@ -4,8 +4,8 @@
     "DOCLINT_HTML_AND_SYNTAX",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+load("//tools/javadoc:javadoc.bzl", "javadoc_library")
+load("//tools/maven:maven.bzl", "dagger_pom_file")
 
 package(default_visibility = ["//:src"])
 
@@ -28,7 +28,7 @@
     ],
 )
 
-pom_file(
+dagger_pom_file(
     name = "pom",
     artifact_id = "dagger-grpc-server-processor",
     artifact_name = "Dagger gRPC Server Processor",
diff --git a/java/dagger/hilt/BUILD b/java/dagger/hilt/BUILD
index 8d25adc..5a2af5b 100644
--- a/java/dagger/hilt/BUILD
+++ b/java/dagger/hilt/BUILD
@@ -12,8 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "POM_VERSION")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 # Description:
 #   A library that wraps the Dagger API to make DI usage and testing easier.
@@ -186,12 +187,12 @@
     name = "artifact-core-lib",
     tags = ["maven_coordinates=com.google.dagger:hilt-core:" + POM_VERSION],
     exports = [
-        ":define_component",
-        ":entry_point",
-        ":generates_root_input",
-        ":install_in",
         ":package_info",
         "//java/dagger:core",
+        "//java/dagger/hilt:define_component",
+        "//java/dagger/hilt:entry_point",
+        "//java/dagger/hilt:generates_root_input",
+        "//java/dagger/hilt:install_in",
         "//java/dagger/hilt/components",
         "//java/dagger/hilt/migration:alias_of",
         "//java/dagger/hilt/migration:disable_install_in_check",
diff --git a/java/dagger/hilt/android/BUILD b/java/dagger/hilt/android/BUILD
index b30f662..d543c3e 100644
--- a/java/dagger/hilt/android/BUILD
+++ b/java/dagger/hilt/android/BUILD
@@ -12,11 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 # Description:
 #   A library based on Hilt that provides standard components and automated injection for Android.
 load("//:build_defs.bzl", "POM_VERSION")
 load("//tools:bazel_compat.bzl", "compat_kt_android_library")
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -68,9 +70,9 @@
         "//java/dagger/hilt/processor/internal/root:root_plugin",
     ],
     exports = [
-        ":activity_retained_lifecycle",
         "//:dagger_with_compiler",
         "//java/dagger/hilt:install_in",
+        "//java/dagger/hilt/android:activity_retained_lifecycle",
         "//java/dagger/hilt/android/components",
         "//java/dagger/hilt/android/internal/builders",
         "//java/dagger/hilt/android/internal/legacy:aggregated_element_proxy",
@@ -247,7 +249,7 @@
         "com.google.guava:guava",
         "javax.annotation:javax.annotation-api",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_exclude_packages = [
         "dagger.hilt.android.internal",
     ],
diff --git a/java/dagger/hilt/android/components/BUILD b/java/dagger/hilt/android/components/BUILD
index 655ccd1..5e52c7f 100644
--- a/java/dagger/hilt/android/components/BUILD
+++ b/java/dagger/hilt/android/components/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Hilt Android components
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 android_library(
diff --git a/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java b/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java
index 11cc89f..4f95c07 100644
--- a/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java
+++ b/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java
@@ -25,5 +25,6 @@
 @DefineComponent.Builder
 public interface FragmentComponentBuilder {
   FragmentComponentBuilder fragment(@BindsInstance Fragment fragment);
+
   FragmentComponent build();
 }
diff --git a/java/dagger/hilt/android/internal/earlyentrypoint/BUILD b/java/dagger/hilt/android/internal/earlyentrypoint/BUILD
index ab1478a..5b5ed32 100644
--- a/java/dagger/hilt/android/internal/earlyentrypoint/BUILD
+++ b/java/dagger/hilt/android/internal/earlyentrypoint/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor that aggregates metadata about Hilt @EarlyEntryPoint annotations
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/internal/legacy/BUILD b/java/dagger/hilt/android/internal/legacy/BUILD
index 0814af0..4b18881 100644
--- a/java/dagger/hilt/android/internal/legacy/BUILD
+++ b/java/dagger/hilt/android/internal/legacy/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Internal Hilt libraries for legacy code.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java b/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java
index 3fa4910..f05fea2 100644
--- a/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java
+++ b/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java
@@ -36,7 +36,9 @@
  * because even the injector interface type is not a valid type if we have a hilt base class.
  *
  */
-public class ActivityComponentManager implements GeneratedComponentManager<Object> {
+public class ActivityComponentManager
+    implements
+        GeneratedComponentManager<Object> {
   /** Entrypoint for {@link ActivityComponentBuilder}. */
   @EntryPoint
   @InstallIn(ActivityRetainedComponent.class)
diff --git a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java b/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
index dc3539c..3f53a6b 100644
--- a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
+++ b/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
@@ -120,6 +120,8 @@
 
   @Override
   public ActivityRetainedComponent generatedComponent() {
+    // TODO(bcorso): don't need the component lock since the component is stored in ViewModel
+    // which does its own locking
     if (component == null) {
       synchronized (componentLock) {
         if (component == null) {
diff --git a/java/dagger/hilt/android/internal/managers/BUILD b/java/dagger/hilt/android/internal/managers/BUILD
index 950b511..ab1321f 100644
--- a/java/dagger/hilt/android/internal/managers/BUILD
+++ b/java/dagger/hilt/android/internal/managers/BUILD
@@ -34,7 +34,9 @@
         "ServiceComponentManager.java",
         "ViewComponentManager.java",
     ],
-    exports = [":saved_state_handle_holder"],
+    exports = [
+        ":saved_state_handle_holder",
+    ],
     deps = [
         ":component_supplier",
         ":saved_state_handle_holder",
diff --git a/java/dagger/hilt/android/internal/testing/BUILD b/java/dagger/hilt/android/internal/testing/BUILD
index 899ab94..dea7ebc 100644
--- a/java/dagger/hilt/android/internal/testing/BUILD
+++ b/java/dagger/hilt/android/internal/testing/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Internal Hilt android testing libraries
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/internal/uninstallmodules/BUILD b/java/dagger/hilt/android/internal/uninstallmodules/BUILD
index 583964b..1a49dc7 100644
--- a/java/dagger/hilt/android/internal/uninstallmodules/BUILD
+++ b/java/dagger/hilt/android/internal/uninstallmodules/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor that aggregates metadata about Hilt @UninstallModules annotations
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/lifecycle/BUILD b/java/dagger/hilt/android/lifecycle/BUILD
index 26394f0..1c7b23b 100644
--- a/java/dagger/hilt/android/lifecycle/BUILD
+++ b/java/dagger/hilt/android/lifecycle/BUILD
@@ -15,6 +15,7 @@
 # Description:
 #   Hilt ViewModel integration.
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//tools:bazel_compat.bzl", "compat_kt_android_library")
 
 package(default_visibility = ["//:src"])
diff --git a/java/dagger/hilt/android/migration/BUILD b/java/dagger/hilt/android/migration/BUILD
index 3694560..6ee7465 100644
--- a/java/dagger/hilt/android/migration/BUILD
+++ b/java/dagger/hilt/android/migration/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Helpers for migrating to Hilt.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 android_library(
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle
deleted file mode 100644
index 5509261..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
-  id 'org.jetbrains.kotlin.jvm'
-}
-
-compileKotlin {
-  kotlinOptions {
-    jvmTarget = 11
-  }
-}
-
-dependencies {
-  implementation project(':agp-wrapper')
-  compileOnly gradleApi()
-  compileOnly "com.android.tools.build:gradle:7.0.0"
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt
deleted file mode 100644
index 1f50794..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.variant.AndroidComponentsExtension
-import com.android.build.api.variant.ApplicationVariant
-import com.android.build.api.variant.LibraryVariant
-import org.gradle.api.Project
-
-class AndroidComponentsExtensionCompatApi70Impl(
-  private val project: Project
-) : AndroidComponentsExtensionCompat {
-
-  override fun onAllVariants(block: (ComponentCompat) -> Unit) {
-    val actual = project.extensions.getByType(AndroidComponentsExtension::class.java)
-    actual.onVariants { variant ->
-      block.invoke(ComponentCompatApi70Impl(variant))
-
-      when (variant) {
-        is ApplicationVariant -> variant.androidTest
-        is LibraryVariant -> variant.androidTest
-        else -> null
-      }?.let { block.invoke(ComponentCompatApi70Impl(it)) }
-
-      variant.unitTest?.let { block.invoke(ComponentCompatApi70Impl(it)) }
-    }
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt
deleted file mode 100644
index 36c7d77..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.instrumentation.AsmClassVisitorFactory
-import com.android.build.api.instrumentation.FramesComputationMode
-import com.android.build.api.instrumentation.InstrumentationParameters
-import com.android.build.api.instrumentation.InstrumentationScope
-import com.android.build.api.variant.Component
-
-internal class ComponentCompatApi70Impl(private val component: Component) : ComponentCompat() {
-
-  override val name: String
-    get() = component.name
-
-  @Suppress("UnstableApiUsage") // Due to ASM pipeline APIs
-  override fun <ParamT : InstrumentationParameters> transformClassesWith(
-    classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
-    scope: InstrumentationScope,
-    instrumentationParamsConfig: (ParamT) -> Unit
-  ) {
-    component.transformClassesWith(classVisitorFactoryImplClass, scope, instrumentationParamsConfig)
-  }
-
-  @Suppress("UnstableApiUsage") // Due to ASM pipeline APIs
-  override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
-    component.setAsmFramesComputationMode(mode)
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle
deleted file mode 100644
index 982949a..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
-  id 'org.jetbrains.kotlin.jvm'
-}
-
-compileKotlin {
-  kotlinOptions {
-    jvmTarget = 11
-  }
-}
-
-dependencies {
-  implementation project(':agp-wrapper')
-  compileOnly gradleApi()
-  compileOnly "com.android.tools.build:gradle:7.1.0"
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi71Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi71Impl.kt
deleted file mode 100644
index dc8704f..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi71Impl.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.variant.AndroidComponentsExtension
-import com.android.build.api.variant.HasAndroidTest
-import org.gradle.api.Project
-
-class AndroidComponentsExtensionCompatApi71Impl(
-  private val project: Project
-) : AndroidComponentsExtensionCompat {
-
-  override fun onAllVariants(block: (ComponentCompat) -> Unit) {
-    val actual = project.extensions.getByType(AndroidComponentsExtension::class.java)
-    actual.onVariants { variant ->
-      block.invoke(ComponentCompatApi71Impl(variant))
-
-      (variant as? HasAndroidTest)?.androidTest?.let { block.invoke(ComponentCompatApi71Impl(it)) }
-
-      variant.unitTest?.let { block.invoke(ComponentCompatApi71Impl(it)) }
-    }
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt
deleted file mode 100644
index d7c9658..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.instrumentation.AsmClassVisitorFactory
-import com.android.build.api.instrumentation.FramesComputationMode
-import com.android.build.api.instrumentation.InstrumentationParameters
-import com.android.build.api.instrumentation.InstrumentationScope
-import com.android.build.api.variant.Component
-
-internal class ComponentCompatApi71Impl(private val component: Component) : ComponentCompat() {
-
-  override val name: String
-    get() = component.name
-
-  override fun <ParamT : InstrumentationParameters> transformClassesWith(
-    classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
-    scope: InstrumentationScope,
-    instrumentationParamsConfig: (ParamT) -> Unit
-  ) {
-    component.transformClassesWith(classVisitorFactoryImplClass, scope, instrumentationParamsConfig)
-  }
-
-  override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
-    component.setAsmFramesComputationMode(mode)
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle
deleted file mode 100644
index e0331c2..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
-  id 'org.jetbrains.kotlin.jvm'
-}
-
-compileKotlin {
-  kotlinOptions {
-    jvmTarget = 11
-  }
-}
-
-dependencies {
-  implementation project(':agp-wrapper')
-  compileOnly gradleApi()
-  compileOnly "com.android.tools.build:gradle:7.2.0"
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi72Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi72Impl.kt
deleted file mode 100644
index 24ee5fd..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi72Impl.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.variant.AndroidComponentsExtension
-import com.android.build.api.variant.HasAndroidTest
-import org.gradle.api.Project
-
-class AndroidComponentsExtensionCompatApi72Impl(
-  private val project: Project
-) : AndroidComponentsExtensionCompat {
-
-  override fun onAllVariants(block: (ComponentCompat) -> Unit) {
-    val actual = project.extensions.getByType(AndroidComponentsExtension::class.java)
-    actual.onVariants { variant ->
-      block.invoke(ComponentCompatApi72Impl(variant))
-
-      (variant as? HasAndroidTest)?.androidTest?.let { block.invoke(ComponentCompatApi72Impl(it)) }
-
-      variant.unitTest?.let { block.invoke(ComponentCompatApi72Impl(it)) }
-    }
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt
deleted file mode 100644
index ac4abf5..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.instrumentation.AsmClassVisitorFactory
-import com.android.build.api.instrumentation.FramesComputationMode
-import com.android.build.api.instrumentation.InstrumentationParameters
-import com.android.build.api.instrumentation.InstrumentationScope
-import com.android.build.api.variant.Component
-
-internal class ComponentCompatApi72Impl(private val component: Component) : ComponentCompat() {
-
-  override val name: String
-    get() = component.name
-
-  override fun <ParamT : InstrumentationParameters> transformClassesWith(
-    classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
-    scope: InstrumentationScope,
-    instrumentationParamsConfig: (ParamT) -> Unit
-  ) {
-    component.instrumentation.transformClassesWith(
-      classVisitorFactoryImplClass,
-      scope,
-      instrumentationParamsConfig
-    )
-  }
-
-  override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
-    component.instrumentation.setAsmFramesComputationMode(mode)
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle
deleted file mode 100644
index f270efb..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle
+++ /dev/null
@@ -1,21 +0,0 @@
-plugins {
-  id 'org.jetbrains.kotlin.jvm'
-}
-
-compileKotlin {
-  kotlinOptions {
-    jvmTarget = 11
-  }
-}
-
-dependencies {
-  api project(':agp-wrapper')
-  implementation project(':agp-wrapper-7-0')
-  implementation project(':agp-wrapper-7-1')
-  implementation project(':agp-wrapper-7-2')
-  compileOnly gradleApi()
-  compileOnly "com.android.tools.build:gradle:$agp_version"
-
-  testImplementation 'junit:junit:4.12'
-  testImplementation 'com.google.truth:truth:1.0.1'
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/AGPVersionCompat.kt b/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/AGPVersionCompat.kt
deleted file mode 100644
index 3ddd484..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/AGPVersionCompat.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import org.gradle.api.Project
-
-fun getAndroidComponentsExtension(project: Project): AndroidComponentsExtensionCompat {
-  val version = SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION
-  return when {
-    version >= SimpleAGPVersion(7, 2) -> {
-      AndroidComponentsExtensionCompatApi72Impl(project)
-    }
-    version >= SimpleAGPVersion(7, 1) -> {
-      AndroidComponentsExtensionCompatApi71Impl(project)
-    }
-    version >= SimpleAGPVersion(7, 0) -> {
-      AndroidComponentsExtensionCompatApi70Impl(project)
-    }
-    else -> {
-      error("Android Gradle Plugin $version is not supported")
-    }
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt b/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
deleted file mode 100644
index 6c5e781..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-/**
- * Simple Android Gradle Plugin version class since there is no public API one. b/175816217
- */
-data class SimpleAGPVersion(
-  val major: Int,
-  val minor: Int,
-) : Comparable<SimpleAGPVersion> {
-
-  override fun toString(): String {
-    return "$major.$minor"
-  }
-
-  override fun compareTo(other: SimpleAGPVersion): Int {
-    return compareValuesBy(
-      this,
-      other,
-      compareBy(SimpleAGPVersion::major).thenBy(SimpleAGPVersion::minor)
-    ) { it }
-  }
-
-  companion object {
-
-    // TODO(danysantiago): Migrate to AndroidPluginVersion once it is available (b/175816217)
-    val ANDROID_GRADLE_PLUGIN_VERSION by lazy {
-      val clazz =
-        findClass("com.android.Version")
-          ?: findClass("com.android.builder.model.Version")
-      if (clazz != null) {
-        return@lazy parse(clazz.getField("ANDROID_GRADLE_PLUGIN_VERSION").get(null) as String)
-      }
-      error(
-        "Unable to obtain AGP version. It is likely that the AGP version being used is too old."
-      )
-    }
-
-    fun parse(version: String?) =
-      tryParse(version) ?: error("Unable to parse AGP version: $version")
-
-    private fun tryParse(version: String?): SimpleAGPVersion? {
-      if (version == null) {
-        return null
-      }
-
-      val parts = version.split('.')
-      if (parts.size == 1) {
-        return SimpleAGPVersion(parts[0].toInt(), 0)
-      }
-
-      return SimpleAGPVersion(parts[0].toInt(), parts[1].toInt())
-    }
-
-    private fun findClass(fqName: String) =
-      try {
-        Class.forName(fqName)
-      } catch (ex: ClassNotFoundException) {
-        null
-      }
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/test/kotlin/util/SimpleAGPVersionTest.kt b/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/test/kotlin/util/SimpleAGPVersionTest.kt
deleted file mode 100644
index 155cb0c..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/test/kotlin/util/SimpleAGPVersionTest.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 util
-
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.plugin.util.SimpleAGPVersion
-import org.junit.Test
-
-class SimpleAGPVersionTest {
-
-  @Test
-  fun parsing() {
-    assertThat(SimpleAGPVersion.parse("4.2"))
-      .isEqualTo(SimpleAGPVersion(4, 2))
-    assertThat(SimpleAGPVersion.parse("4.2.1"))
-      .isEqualTo(SimpleAGPVersion(4, 2))
-    assertThat(SimpleAGPVersion.parse("7.0.0-alpha01"))
-      .isEqualTo(SimpleAGPVersion(7, 0))
-  }
-
-  @Test
-  fun comparing() {
-    assertThat(SimpleAGPVersion(4, 2))
-      .isEqualTo(SimpleAGPVersion(4, 2))
-    assertThat(SimpleAGPVersion(4, 2))
-      .isGreaterThan(SimpleAGPVersion(3, 4))
-    assertThat(SimpleAGPVersion(4, 2))
-      .isLessThan(SimpleAGPVersion(7, 0))
-
-    assertThat(SimpleAGPVersion.parse("4.2.1"))
-      .isEqualTo(SimpleAGPVersion.parse("4.2.2"))
-    assertThat(SimpleAGPVersion.parse("4.2.1"))
-      .isGreaterThan(SimpleAGPVersion.parse("3.4.1"))
-    assertThat(SimpleAGPVersion.parse("4.2.1"))
-      .isLessThan(SimpleAGPVersion.parse("7.0.1"))
-
-    assertThat(SimpleAGPVersion.parse("4.2.1"))
-      .isLessThan(SimpleAGPVersion.parse("7.0.0-alpha01"))
-    assertThat(SimpleAGPVersion.parse("7.0.0-alpha01"))
-      .isEqualTo(SimpleAGPVersion.parse("7.0.0-alpha02"))
-  }
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle
deleted file mode 100644
index d8238e8..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle
+++ /dev/null
@@ -1,14 +0,0 @@
-plugins {
-  id 'org.jetbrains.kotlin.jvm'
-}
-
-compileKotlin {
- kotlinOptions {
-   jvmTarget = 11
- }
-}
-
-dependencies {
-  compileOnly gradleApi()
-  compileOnly "com.android.tools.build:gradle:$agp_version"
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompat.kt b/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompat.kt
deleted file mode 100644
index cdbeef2..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompat.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-/**
- * Compatibility version of [com.android.build.api.variant.AndroidComponentsExtension]
- * - In AGP 4.2 its package is 'com.android.build.api.extension'
- * - In AGP 7.0 its packages is 'com.android.build.api.variant'
- */
-interface AndroidComponentsExtensionCompat {
-
-  /**
-   * A combined compatibility function of
-   * [com.android.build.api.variant.AndroidComponentsExtension.onVariants] that includes also
-   * [AndroidTest] and [UnitTest] variants.
-   */
-  fun onAllVariants(block: (ComponentCompat) -> Unit)
-}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt b/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt
deleted file mode 100644
index 1f0d589..0000000
--- a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger 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
- *
- * 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 dagger.hilt.android.plugin.util
-
-import com.android.build.api.instrumentation.AsmClassVisitorFactory
-import com.android.build.api.instrumentation.FramesComputationMode
-import com.android.build.api.instrumentation.InstrumentationParameters
-import com.android.build.api.instrumentation.InstrumentationScope
-import java.io.File
-import org.gradle.api.Project
-
-/**
- * Compatibility version of [com.android.build.api.variant.Component]
- * - In AGP 4.2 its package is 'com.android.build.api.component'
- * - In AGP 7.0 its packages is 'com.android.build.api.variant'
- */
-abstract class ComponentCompat {
-
-  /** Redeclaration of [com.android.build.api.variant.ComponentIdentity.name] */
-  abstract val name: String
-
-  /** Redeclaration of [com.android.build.api.variant.Component.transformClassesWith] */
-  abstract fun <ParamT : InstrumentationParameters> transformClassesWith(
-    classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
-    scope: InstrumentationScope,
-    instrumentationParamsConfig: (ParamT) -> Unit
-  )
-
-  /** Redeclaration of [com.android.build.api.variant.Component.setAsmFramesComputationMode] */
-  abstract fun setAsmFramesComputationMode(mode: FramesComputationMode)
-}
diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle
index 685ea7e..e40d4ed 100644
--- a/java/dagger/hilt/android/plugin/build.gradle
+++ b/java/dagger/hilt/android/plugin/build.gradle
@@ -1,8 +1,8 @@
 buildscript {
   ext {
-    kotlin_version = "1.9.20"
-    agp_version = System.getenv('AGP_VERSION') ?: "7.2.0"
-    ksp_version = "$kotlin_version-1.0.14"
+    kotlin_version = "2.0.21"
+    agp_version = System.getenv('AGP_VERSION') ?: "8.1.1"
+    ksp_version = "$kotlin_version-1.0.28"
     pluginArtifactId = 'hilt-android-gradle-plugin'
     pluginId = 'com.google.dagger.hilt.android'
   }
@@ -12,9 +12,7 @@
   id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
   id 'java-gradle-plugin'
   id 'maven-publish'
-  // Use shadow version >= 7.1.1 to get log4j vulnerability patches:
-  //   https://github.com/johnrengelman/shadow/releases/tag/7.1.1
-  id 'com.github.johnrengelman.shadow' version '7.1.1'
+  id 'com.github.johnrengelman.shadow' version '8.1.1'
   id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
 }
 
diff --git a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
index aa991fc..e1bef7e 100644
--- a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
+++ b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/plugin/main/build.gradle b/java/dagger/hilt/android/plugin/main/build.gradle
index 035ecea..bb954f7 100644
--- a/java/dagger/hilt/android/plugin/main/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/build.gradle
@@ -59,12 +59,16 @@
 }
 
 dependencies {
-  shadowed project(':agp-wrapper-impl')
+  // Include the shared library containing the APIs in
+  // dagger.hilt.processor.internal.root.ir.
   shadowed fileTree(dir: 'libs', include: '*.jar')
-  implementation gradleApi()
+  // Use compile-only for other plugin dependencies to avoid brining those
+  // to projects that don't use them.
   compileOnly "com.android.tools.build:gradle:$agp_version"
   compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
   compileOnly "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"
+
+  implementation gradleApi()
   implementation 'org.ow2.asm:asm:9.6'
   implementation "com.squareup:javapoet:1.13.0"
 
@@ -85,12 +89,12 @@
   it.pluginClasspath.from(configurations.testPluginCompile)
 }
 
-compileKotlin {
-  kotlinOptions {
+kotlin {
+  compilerOptions {
     allWarningsAsErrors = true
-    freeCompilerArgs += [ "-opt-in=kotlin.ExperimentalStdlibApi" ]
-    jvmTarget = 11
+    freeCompilerArgs.add("-opt-in=kotlin.ExperimentalStdlibApi")
   }
+  jvmToolchain(17)
 }
 
 // Imports a shared library from the main project. The library and its classes
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
index 7b03e43..34a80d1 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
@@ -16,27 +16,34 @@
 
 package dagger.hilt.android.plugin
 
+import com.android.build.api.AndroidPluginVersion
 import com.android.build.api.instrumentation.FramesComputationMode
 import com.android.build.api.instrumentation.InstrumentationScope
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.api.variant.ApplicationAndroidComponentsExtension
+import com.android.build.api.variant.Component
+import com.android.build.api.variant.HasAndroidTest
+import com.android.build.api.variant.HasUnitTest
+import com.android.build.api.variant.LibraryAndroidComponentsExtension
+import com.android.build.api.variant.TestAndroidComponentsExtension
 import com.android.build.gradle.AppExtension
 import com.android.build.gradle.BaseExtension
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.TestExtension
-import com.android.build.gradle.api.AndroidBasePlugin
 import com.android.build.gradle.tasks.JdkImageInput
 import dagger.hilt.android.plugin.task.AggregateDepsTask
-import dagger.hilt.android.plugin.util.AggregatedPackagesTransform
-import dagger.hilt.android.plugin.util.ComponentCompat
-import dagger.hilt.android.plugin.util.CopyTransform
-import dagger.hilt.android.plugin.util.SimpleAGPVersion
+import dagger.hilt.android.plugin.transform.AggregatedPackagesTransform
+import dagger.hilt.android.plugin.transform.AndroidEntryPointClassVisitor
+import dagger.hilt.android.plugin.transform.CopyTransform
 import dagger.hilt.android.plugin.util.addJavaTaskProcessorOptions
 import dagger.hilt.android.plugin.util.addKaptTaskProcessorOptions
 import dagger.hilt.android.plugin.util.addKspTaskProcessorOptions
 import dagger.hilt.android.plugin.util.capitalize
-import dagger.hilt.android.plugin.util.getAndroidComponentsExtension
+import dagger.hilt.android.plugin.util.forEachRootVariant
 import dagger.hilt.android.plugin.util.getKaptConfigName
 import dagger.hilt.android.plugin.util.getKspConfigName
 import dagger.hilt.android.plugin.util.isKspTask
+import dagger.hilt.android.plugin.util.onAllVariants
 import dagger.hilt.processor.internal.optionvalues.GradleProjectType
 import javax.inject.Inject
 import org.gradle.api.JavaVersion
@@ -49,23 +56,21 @@
 import org.gradle.api.provider.ProviderFactory
 import org.gradle.api.tasks.compile.JavaCompile
 import org.gradle.process.CommandLineArgumentProvider
-import org.gradle.util.GradleVersion
 import org.objectweb.asm.Opcodes
 
 /**
- * A Gradle plugin that checks if the project is an Android project and if so, registers a
- * bytecode transformation.
+ * A Gradle plugin that checks if the project is an Android project and if so, registers a bytecode
+ * transformation.
  *
  * The plugin also passes an annotation processor option to disable superclass validation for
  * classes annotated with `@AndroidEntryPoint` since the registered transform by this plugin will
  * update the superclass.
  */
-class HiltGradlePlugin @Inject constructor(
-  private val providers: ProviderFactory
-) : Plugin<Project> {
+class HiltGradlePlugin @Inject constructor(private val providers: ProviderFactory) :
+  Plugin<Project> {
   override fun apply(project: Project) {
     var configured = false
-    project.plugins.withType(AndroidBasePlugin::class.java) {
+    project.plugins.withId("com.android.base") {
       configured = true
       configureHilt(project)
     }
@@ -80,80 +85,59 @@
   }
 
   private fun configureHilt(project: Project) {
-    val hiltExtension = project.extensions.create(
-      HiltExtension::class.java, "hilt", HiltExtensionImpl::class.java
-    )
-    if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(7, 0)) {
-      error("The Hilt Android Gradle plugin is only compatible with Android Gradle plugin (AGP) " +
-              "version 7.0 or higher (found ${SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION}).")
+    val hiltExtension =
+      project.extensions.create(HiltExtension::class.java, "hilt", HiltExtensionImpl::class.java)
+
+    val androidExtension = project.extensions.findByType(AndroidComponentsExtension::class.java)
+    check(androidExtension != null) { "Could not find the Android Gradle Plugin (AGP) extension." }
+    check(androidExtension.pluginVersion >= AndroidPluginVersion(8, 1)) {
+      "The Hilt Android Gradle plugin is only compatible with Android Gradle plugin (AGP) " +
+        "version 8.1.0 or higher (found ${androidExtension.pluginVersion})."
     }
+
     configureDependencyTransforms(project)
     configureCompileClasspath(project, hiltExtension)
-    configureBytecodeTransformASM(project)
+    configureBytecodeTransformASM(androidExtension)
     configureAggregatingTask(project, hiltExtension)
-    configureProcessorFlags(project, hiltExtension)
+    configureProcessorFlags(project, hiltExtension, androidExtension)
   }
 
   // Configures Gradle dependency transforms.
-  private fun configureDependencyTransforms(project: Project) = project.dependencies.apply {
-    registerTransform(CopyTransform::class.java) { spec ->
-      // Java/Kotlin library projects offer an artifact of type 'jar'.
-      spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
-      // Android library projects (with or without Kotlin) offer an artifact of type
-      // 'android-classes', which AGP can offer as a jar.
-      spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "android-classes")
-      spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+  private fun configureDependencyTransforms(project: Project) =
+    project.dependencies.apply {
+      registerTransform(CopyTransform::class.java) { spec ->
+        // Java/Kotlin library projects offer an artifact of type 'jar'.
+        spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
+        // Android library projects (with or without Kotlin) offer an artifact of type
+        // 'android-classes', which AGP can offer as a jar.
+        spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "android-classes")
+        spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+      }
+      registerTransform(CopyTransform::class.java) { spec ->
+        // File Collection dependencies might be an artifact of type 'directory', e.g. when
+        // adding as a dep the destination directory of the JavaCompile task.
+        spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "directory")
+        spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+      }
+      registerTransform(AggregatedPackagesTransform::class.java) { spec ->
+        spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+        spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, AGGREGATED_HILT_ARTIFACT_TYPE_VALUE)
+      }
     }
-    registerTransform(CopyTransform::class.java) { spec ->
-      // File Collection dependencies might be an artifact of type 'directory', e.g. when
-      // adding as a dep the destination directory of the JavaCompile task.
-      spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "directory")
-      spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
-    }
-    registerTransform(AggregatedPackagesTransform::class.java) { spec ->
-      spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
-      spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, AGGREGATED_HILT_ARTIFACT_TYPE_VALUE)
-    }
-  }
 
   private fun configureCompileClasspath(project: Project, hiltExtension: HiltExtension) {
-    val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
+    val androidExtension =
+      project.extensions.findByType(BaseExtension::class.java)
+        ?: error("Android BaseExtension not found.")
     androidExtension.forEachRootVariant { variant ->
-      configureVariantCompileClasspath(project, hiltExtension, androidExtension, variant)
-    }
-  }
-
-  // Invokes the [block] function for each Android variant that is considered a Hilt root, where
-  // dependencies are aggregated and components are generated.
-  private fun BaseExtension.forEachRootVariant(
-    @Suppress("DEPRECATION") block: (variant: com.android.build.gradle.api.BaseVariant) -> Unit
-  ) {
-    when (this) {
-      is AppExtension -> {
-        // For an app project we configure the app variant and both androidTest and unitTest
-        // variants, Hilt components are generated in all of them.
-        applicationVariants.all { block(it) }
-        testVariants.all { block(it) }
-        unitTestVariants.all { block(it) }
-      }
-      is LibraryExtension -> {
-        // For a library project, only the androidTest and unitTest variant are configured since
-        // Hilt components are not generated in a library.
-        testVariants.all { block(it) }
-        unitTestVariants.all { block(it) }
-      }
-      is TestExtension -> {
-        applicationVariants.all { block(it) }
-      }
-      else -> error("Hilt plugin does not know how to configure '$this'")
+      configureVariantCompileClasspath(project, hiltExtension, variant)
     }
   }
 
   private fun configureVariantCompileClasspath(
     project: Project,
     hiltExtension: HiltExtension,
-    androidExtension: BaseExtension,
-    @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant
+    @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant,
   ) {
     if (
       !hiltExtension.enableExperimentalClasspathAggregation || hiltExtension.enableAggregatingTask
@@ -164,63 +148,34 @@
       return
     }
 
-    if (
-      androidExtension.lintOptions.isCheckReleaseBuilds &&
-      SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(7, 0)
-    ) {
-      // Sadly we have to ask users to disable lint when enableExperimentalClasspathAggregation is
-      // set to true and they are not in AGP 7.0+ since Lint will cause issues during the
-      // configuration phase. See b/158753935 and b/160392650
-      error(
-        "Invalid Hilt plugin configuration: When 'enableExperimentalClasspathAggregation' is " +
-          "enabled 'android.lintOptions.checkReleaseBuilds' has to be set to false unless " +
-          "com.android.tools.build:gradle:7.0.0+ is used."
-      )
-    }
-
-    if (
-      listOf(
-        "android.injected.build.model.only", // Sent by AS 1.0 only
-        "android.injected.build.model.only.advanced", // Sent by AS 1.1+
-        "android.injected.build.model.only.versioned", // Sent by AS 2.4+
-        "android.injected.build.model.feature.full.dependencies", // Sent by AS 2.4+
-        "android.injected.build.model.v2", // Sent by AS 4.2+
-      ).any {
-        // forUseAtConfigurationTime() is deprecated in 7.4 and later:
-        // https://docs.gradle.org/current/userguide/upgrading_version_7.html#changes_7.4
-        if (GradleVersion.version(project.gradle.gradleVersion) < GradleVersion.version("7.4.0")) {
-          @Suppress("DEPRECATION")
-          providers.gradleProperty(it).forUseAtConfigurationTime().isPresent
-        } else {
-          providers.gradleProperty(it).isPresent
-        }
-      }
-    ) {
+    if (project.isGradleSyncRunning()) {
       // Do not configure compile classpath when AndroidStudio is building the model (syncing)
       // otherwise it will cause a freeze.
       return
     }
 
     @Suppress("DEPRECATION") // Older variant API is deprecated
-    val runtimeConfiguration = if (variant is com.android.build.gradle.api.TestVariant) {
-      // For Android test variants, the tested runtime classpath is used since the test app has
-      // tested dependencies removed.
-      variant.testedVariant.runtimeConfiguration
-    } else {
-      variant.runtimeConfiguration
-    }
-    val artifactView = runtimeConfiguration.incoming.artifactView { view ->
-      view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
-      view.componentFilter { identifier ->
-        // Filter out the project's classes from the aggregated view since this can cause
-        // issues with Kotlin internal members visibility. b/178230629
-        if (identifier is ProjectComponentIdentifier) {
-          identifier.projectName != project.name
-        } else {
-          true
+    val runtimeConfiguration =
+      if (variant is com.android.build.gradle.api.TestVariant) {
+        // For Android test variants, the tested runtime classpath is used since the test app has
+        // tested dependencies removed.
+        variant.testedVariant.runtimeConfiguration
+      } else {
+        variant.runtimeConfiguration
+      }
+    val artifactView =
+      runtimeConfiguration.incoming.artifactView { view ->
+        view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
+        view.componentFilter { identifier ->
+          // Filter out the project's classes from the aggregated view since this can cause
+          // issues with Kotlin internal members visibility. b/178230629
+          if (identifier is ProjectComponentIdentifier) {
+            identifier.projectName != project.name
+          } else {
+            true
+          }
         }
       }
-    }
 
     // CompileOnly config names don't follow the usual convention:
     // <Variant Name>   -> <Config Name>
@@ -230,33 +185,34 @@
     // release          -> releaseCompileOnly
     // releaseUnitTest  -> testReleaseCompileOnly
     @Suppress("DEPRECATION") // Older variant API is deprecated
-    val compileOnlyConfigName = when (variant) {
-      is com.android.build.gradle.api.TestVariant ->
-        "androidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}CompileOnly"
-      is com.android.build.gradle.api.UnitTestVariant ->
-        "test${variant.name.substringBeforeLast("UnitTest").capitalize()}CompileOnly"
-      else ->
-        "${variant.name}CompileOnly"
-    }
+    val compileOnlyConfigName =
+      when (variant) {
+        is com.android.build.gradle.api.TestVariant ->
+          "androidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}CompileOnly"
+        is com.android.build.gradle.api.UnitTestVariant ->
+          "test${variant.name.substringBeforeLast("UnitTest").capitalize()}CompileOnly"
+        else -> "${variant.name}CompileOnly"
+      }
     project.dependencies.add(compileOnlyConfigName, artifactView.files)
   }
 
-  private fun configureBytecodeTransformASM(project: Project) {
-    fun registerTransform(androidComponent: ComponentCompat) {
-      androidComponent.transformClassesWith(
+  private fun configureBytecodeTransformASM(androidExtension: AndroidComponentsExtension<*, *, *>) {
+    androidExtension.onAllVariants { variantComponent ->
+      variantComponent.instrumentation.transformClassesWith(
         classVisitorFactoryImplClass = AndroidEntryPointClassVisitor.Factory::class.java,
         scope = InstrumentationScope.PROJECT,
-        instrumentationParamsConfig = {}
+        instrumentationParamsConfig = {},
       )
-      androidComponent.setAsmFramesComputationMode(
+      variantComponent.instrumentation.setAsmFramesComputationMode(
         FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
       )
     }
-    getAndroidComponentsExtension(project).onAllVariants { registerTransform(it) }
   }
 
   private fun configureAggregatingTask(project: Project, hiltExtension: HiltExtension) {
-    val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
+    val androidExtension =
+      project.extensions.findByType(BaseExtension::class.java)
+        ?: error("Android BaseExtension not found.")
     androidExtension.forEachRootVariant { variant ->
       configureVariantAggregatingTask(project, hiltExtension, androidExtension, variant)
     }
@@ -266,21 +222,20 @@
     project: Project,
     hiltExtension: HiltExtension,
     androidExtension: BaseExtension,
-    @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant
+    @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant,
   ) {
     if (!hiltExtension.enableAggregatingTask) {
       // Option is not enabled, don't configure aggregating task.
       return
     }
 
-    val hiltCompileConfiguration = project.configurations.create(
-      "hiltCompileOnly${variant.name.capitalize()}"
-    ).apply {
-      description = "Hilt aggregated compile only dependencies for '${variant.name}'"
-      isCanBeConsumed = false
-      isCanBeResolved = true
-      isVisible = false
-    }
+    val hiltCompileConfiguration =
+      project.configurations.create("hiltCompileOnly${variant.name.capitalize()}").apply {
+        description = "Hilt aggregated compile only dependencies for '${variant.name}'"
+        isCanBeConsumed = false
+        isCanBeResolved = true
+        isVisible = false
+      }
     // Add the JavaCompile task classpath and output dir to the config, the task's classpath
     // will contain:
     //  * compileOnly dependencies
@@ -290,165 +245,167 @@
     // TODO(danysantiago): Revisit to support K2 compiler
     project.dependencies.add(
       hiltCompileConfiguration.name,
-      project.files(variant.javaCompileProvider.map { it.classpath })
+      project.files(variant.javaCompileProvider.map { it.classpath }),
     )
     project.dependencies.add(
       hiltCompileConfiguration.name,
-      project.files(variant.javaCompileProvider.map {it.destinationDirectory.get() })
+      project.files(variant.javaCompileProvider.map { it.destinationDirectory.get() }),
     )
 
-    val hiltAnnotationProcessorConfiguration = project.configurations.create(
-      "hiltAnnotationProcessor${variant.name.capitalize()}"
-    ).also { config ->
-      config.description = "Hilt annotation processor classpath for '${variant.name}'"
-      config.isCanBeConsumed = false
-      config.isCanBeResolved = true
-      config.isVisible = false
-      // Add user annotation processor configuration, so that SPI plugins and other processors
-      // are discoverable.
-      val apConfigurations: List<Configuration> = buildList {
-        add(variant.annotationProcessorConfiguration)
-        project.plugins.withId("kotlin-kapt") {
-          project.configurations.findByName(getKaptConfigName(variant))?.let { add(it) }
+    val hiltAnnotationProcessorConfiguration =
+      project.configurations.create("hiltAnnotationProcessor${variant.name.capitalize()}").also {
+        config ->
+        config.description = "Hilt annotation processor classpath for '${variant.name}'"
+        config.isCanBeConsumed = false
+        config.isCanBeResolved = true
+        config.isVisible = false
+        // Add user annotation processor configuration, so that SPI plugins and other processors
+        // are discoverable.
+        val apConfigurations: List<Configuration> = buildList {
+          add(variant.annotationProcessorConfiguration)
+          project.plugins.withId("kotlin-kapt") {
+            project.configurations.findByName(getKaptConfigName(variant))?.let { add(it) }
+          }
+          project.plugins.withId("com.google.devtools.ksp") {
+            // Add the main 'ksp' config since the variant aware config does not extend main.
+            // https://github.com/google/ksp/issues/1433
+            project.configurations.findByName("ksp")?.let { add(it) }
+            project.configurations.findByName(getKspConfigName(variant))?.let { add(it) }
+          }
         }
-        project.plugins.withId("com.google.devtools.ksp") {
-          // Add the main 'ksp' config since the variant aware config does not extend main.
-          // https://github.com/google/ksp/issues/1433
-          project.configurations.findByName("ksp")?.let { add(it) }
-          project.configurations.findByName(getKspConfigName(variant))?.let { add(it) }
-        }
+        config.extendsFrom(*apConfigurations.toTypedArray())
+        // Add hilt-compiler even though it might be in the AP configurations already.
+        project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION")
       }
-      config.extendsFrom(*apConfigurations.toTypedArray())
-      // Add hilt-compiler even though it might be in the AP configurations already.
-      project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION")
-    }
 
     fun getInputClasspath(artifactAttributeValue: String) =
       buildList<Configuration> {
-        @Suppress("DEPRECATION") // Older variant API is deprecated
-        if (variant is com.android.build.gradle.api.TestVariant) {
-          add(variant.testedVariant.runtimeConfiguration)
+          @Suppress("DEPRECATION") // Older variant API is deprecated
+          if (variant is com.android.build.gradle.api.TestVariant) {
+            add(variant.testedVariant.runtimeConfiguration)
+          }
+          add(variant.runtimeConfiguration)
+          add(hiltCompileConfiguration)
         }
-        add(variant.runtimeConfiguration)
-        add(hiltCompileConfiguration)
-      }.map { configuration ->
-        configuration.incoming.artifactView { view ->
-          view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, artifactAttributeValue)
-        }.files
-      }.let {
-        project.files(*it.toTypedArray())
-      }
+        .map { configuration ->
+          configuration.incoming
+            .artifactView { view ->
+              view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, artifactAttributeValue)
+            }
+            .files
+        }
+        .let { project.files(*it.toTypedArray()) }
 
-    val aggregatingTask = project.tasks.register(
-      "hiltAggregateDeps${variant.name.capitalize()}",
-      AggregateDepsTask::class.java
-    ) {
-      it.compileClasspath.setFrom(getInputClasspath(AGGREGATED_HILT_ARTIFACT_TYPE_VALUE))
-      it.outputDir.set(
-        project.file(project.buildDir.resolve("generated/hilt/component_trees/${variant.name}/"))
-      )
-      @Suppress("DEPRECATION") // Older variant API is deprecated
-      it.testEnvironment.set(
-        variant is com.android.build.gradle.api.TestVariant ||
-          variant is com.android.build.gradle.api.UnitTestVariant ||
-          androidExtension is com.android.build.gradle.TestExtension
-      )
-      it.crossCompilationRootValidationDisabled.set(
-        hiltExtension.disableCrossCompilationRootValidation
-      )
-      if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION >= SimpleAGPVersion(7, 1)) {
+    val aggregatingTask =
+      project.tasks.register(
+        "hiltAggregateDeps${variant.name.capitalize()}",
+        AggregateDepsTask::class.java,
+      ) {
+        it.compileClasspath.setFrom(getInputClasspath(AGGREGATED_HILT_ARTIFACT_TYPE_VALUE))
+        it.outputDir.set(
+          project.file(project.buildDir.resolve("generated/hilt/component_trees/${variant.name}/"))
+        )
+        @Suppress("DEPRECATION") // Older variant API is deprecated
+        it.testEnvironment.set(
+          variant is com.android.build.gradle.api.TestVariant ||
+            variant is com.android.build.gradle.api.UnitTestVariant ||
+            androidExtension is com.android.build.gradle.TestExtension
+        )
+        it.crossCompilationRootValidationDisabled.set(
+          hiltExtension.disableCrossCompilationRootValidation
+        )
         it.asmApiVersion.set(Opcodes.ASM9)
       }
-    }
 
-    val componentClasses = project.files(
-      project.buildDir.resolve("intermediates/hilt/component_classes/${variant.name}/")
-    )
-    val componentsJavaCompileTask = project.tasks.register(
-      "hiltJavaCompile${variant.name.capitalize()}",
-      JavaCompile::class.java
-    ) { compileTask ->
-      compileTask.source = aggregatingTask.map { it.outputDir.asFileTree }.get()
-      // Configure the input classpath based on Java 9 compatibility, specifically for Java 9 the
-      // android.jar is now included in the input classpath instead of the bootstrapClasspath.
-      // See: com/android/build/gradle/tasks/JavaCompileUtils.kt
-      val mainBootstrapClasspath =
-        variant.javaCompileProvider.map { it.options.bootstrapClasspath ?: project.files() }.get()
-      if (
-        JavaVersion.current().isJava9Compatible &&
-        androidExtension.compileOptions.targetCompatibility.isJava9Compatible
-      ) {
-        compileTask.classpath =
-          getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE).plus(mainBootstrapClasspath)
-        //  Copies argument providers from original task, which should contain the JdkImageInput
-        variant.javaCompileProvider.get().let { originalCompileTask ->
-          originalCompileTask.options.compilerArgumentProviders
-            .filter { 
-              it is HiltCommandLineArgumentProvider || it is JdkImageInput
-            }
-            .forEach {
-              compileTask.options.compilerArgumentProviders.add(it)
-            }
-        }
-        compileTask.options.compilerArgs.add("-XDstringConcat=inline")
-      } else {
-        compileTask.classpath = getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE)
-        compileTask.options.bootstrapClasspath = mainBootstrapClasspath
-      }
-      compileTask.destinationDirectory.set(componentClasses.singleFile)
-      compileTask.options.apply {
-        annotationProcessorPath = hiltAnnotationProcessorConfiguration
-        generatedSourceOutputDirectory.set(
-          project.file(
-            project.buildDir.resolve("generated/hilt/component_sources/${variant.name}/")
-          )
-        )
+    val componentClasses =
+      project.files(
+        project.buildDir.resolve("intermediates/hilt/component_classes/${variant.name}/")
+      )
+    val componentsJavaCompileTask =
+      project.tasks.register(
+        "hiltJavaCompile${variant.name.capitalize()}",
+        JavaCompile::class.java,
+      ) { compileTask ->
+        compileTask.source = aggregatingTask.map { it.outputDir.asFileTree }.get()
+        // Configure the input classpath based on Java 9 compatibility, specifically for Java 9 the
+        // android.jar is now included in the input classpath instead of the bootstrapClasspath.
+        // See: com/android/build/gradle/tasks/JavaCompileUtils.kt
+        val mainBootstrapClasspath =
+          variant.javaCompileProvider.map { it.options.bootstrapClasspath ?: project.files() }.get()
         if (
-          JavaVersion.current().isJava8Compatible &&
-          androidExtension.compileOptions.targetCompatibility.isJava8Compatible
+          JavaVersion.current().isJava9Compatible &&
+            androidExtension.compileOptions.targetCompatibility.isJava9Compatible
         ) {
-          compilerArgs.add("-parameters")
+          compileTask.classpath =
+            getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE).plus(mainBootstrapClasspath)
+          //  Copies argument providers from original task, which should contain the JdkImageInput
+          variant.javaCompileProvider.get().let { originalCompileTask ->
+            originalCompileTask.options.compilerArgumentProviders
+              .filter { it is HiltCommandLineArgumentProvider || it is JdkImageInput }
+              .forEach { compileTask.options.compilerArgumentProviders.add(it) }
+          }
+          compileTask.options.compilerArgs.add("-XDstringConcat=inline")
+        } else {
+          compileTask.classpath = getInputClasspath(DAGGER_ARTIFACT_TYPE_VALUE)
+          compileTask.options.bootstrapClasspath = mainBootstrapClasspath
         }
-        compilerArgs.add("-Adagger.fastInit=enabled")
-        compilerArgs.add("-Adagger.hilt.internal.useAggregatingRootProcessor=false")
-        compilerArgs.add("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
-        encoding = androidExtension.compileOptions.encoding
+        compileTask.destinationDirectory.set(componentClasses.singleFile)
+        compileTask.options.apply {
+          annotationProcessorPath = hiltAnnotationProcessorConfiguration
+          generatedSourceOutputDirectory.set(
+            project.file(
+              project.buildDir.resolve("generated/hilt/component_sources/${variant.name}/")
+            )
+          )
+          if (
+            JavaVersion.current().isJava8Compatible &&
+              androidExtension.compileOptions.targetCompatibility.isJava8Compatible
+          ) {
+            compilerArgs.add("-parameters")
+          }
+          compilerArgs.add("-Adagger.fastInit=enabled")
+          compilerArgs.add("-Adagger.hilt.internal.useAggregatingRootProcessor=false")
+          compilerArgs.add("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
+          encoding = androidExtension.compileOptions.encoding
+        }
+        compileTask.sourceCompatibility =
+          androidExtension.compileOptions.sourceCompatibility.toString()
+        compileTask.targetCompatibility =
+          androidExtension.compileOptions.targetCompatibility.toString()
       }
-      compileTask.sourceCompatibility =
-        androidExtension.compileOptions.sourceCompatibility.toString()
-      compileTask.targetCompatibility =
-        androidExtension.compileOptions.targetCompatibility.toString()
-    }
     componentClasses.builtBy(componentsJavaCompileTask)
 
     variant.registerPostJavacGeneratedBytecode(componentClasses)
   }
 
-  private fun configureProcessorFlags(project: Project, hiltExtension: HiltExtension) {
-    val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
-    val projectType = when (androidExtension) {
-      is AppExtension -> GradleProjectType.APP
-      is LibraryExtension -> GradleProjectType.LIBRARY
-      is TestExtension -> GradleProjectType.TEST
-      else -> error("Hilt plugin does not know how to configure '$this'")
-    }
+  private fun configureProcessorFlags(
+    project: Project,
+    hiltExtension: HiltExtension,
+    androidExtension: AndroidComponentsExtension<*, *, *>,
+  ) {
+    val projectType =
+      when (androidExtension) {
+        is ApplicationAndroidComponentsExtension -> GradleProjectType.APP
+        is LibraryAndroidComponentsExtension -> GradleProjectType.LIBRARY
+        is TestAndroidComponentsExtension -> GradleProjectType.TEST
+        else -> error("Hilt plugin does not know how to configure '$this'")
+      }
 
-    getAndroidComponentsExtension(project).onAllVariants { component ->
+    androidExtension.onAllVariants { variantComponent ->
       // Pass annotation processor flags via a CommandLineArgumentProvider so that plugin
       // options defined in the extension are populated from the user's build file.
       val argsProducer: (Task) -> CommandLineArgumentProvider = { task ->
         HiltCommandLineArgumentProvider(
           forKsp = task.isKspTask(),
           projectType = projectType,
-          enableAggregatingTask =
-            hiltExtension.enableAggregatingTask,
+          enableAggregatingTask = hiltExtension.enableAggregatingTask,
           disableCrossCompilationRootValidation =
-            hiltExtension.disableCrossCompilationRootValidation
+            hiltExtension.disableCrossCompilationRootValidation,
         )
       }
-      addJavaTaskProcessorOptions(project, component, argsProducer)
-      addKaptTaskProcessorOptions(project, component, argsProducer)
-      addKspTaskProcessorOptions(project, component, argsProducer)
+      addJavaTaskProcessorOptions(project, variantComponent, argsProducer)
+      addKaptTaskProcessorOptions(project, variantComponent, argsProducer)
+      addKspTaskProcessorOptions(project, variantComponent, argsProducer)
     }
   }
 
@@ -457,15 +414,16 @@
     if (project.state.failure != null) {
       return
     }
-    val dependencies = project.configurations
-      .filterNot {
-        // Exclude plugin created config since plugin adds the deps to them.
-        it.name.startsWith("hiltAnnotationProcessor") ||
-          it.name.startsWith("hiltCompileOnly")
-      }
-      .flatMap { configuration ->
-        configuration.dependencies.map { dependency -> dependency.group to dependency.name }
-      }.toSet()
+    val dependencies =
+      project.configurations
+        .filterNot {
+          // Exclude plugin created config since plugin adds the deps to them.
+          it.name.startsWith("hiltAnnotationProcessor") || it.name.startsWith("hiltCompileOnly")
+        }
+        .flatMap { configuration ->
+          configuration.dependencies.map { dependency -> dependency.group to dependency.name }
+        }
+        .toSet()
     fun getMissingDepMsg(depCoordinate: String): String =
       "The Hilt Android Gradle plugin is applied but no $depCoordinate dependency was found."
     if (!dependencies.contains(LIBRARY_GROUP to "hilt-android")) {
@@ -473,20 +431,30 @@
     }
     if (
       !dependencies.contains(LIBRARY_GROUP to "hilt-android-compiler") &&
-      !dependencies.contains(LIBRARY_GROUP to "hilt-compiler")
+        !dependencies.contains(LIBRARY_GROUP to "hilt-compiler")
     ) {
       error(getMissingDepMsg("$LIBRARY_GROUP:hilt-compiler"))
     }
   }
 
-  private fun Project.baseExtension(): BaseExtension?
-      = extensions.findByType(BaseExtension::class.java)
-
   companion object {
     private val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
     const val DAGGER_ARTIFACT_TYPE_VALUE = "jar-for-dagger"
     const val AGGREGATED_HILT_ARTIFACT_TYPE_VALUE = "aggregated-jar-for-hilt"
 
     const val LIBRARY_GROUP = "com.google.dagger"
+
+    private fun Project.isGradleSyncRunning() =
+      gradleSyncProps.any { property ->
+        providers.gradleProperty(property).map { it.toBoolean() }.orElse(false).get()
+      }
+
+    private val gradleSyncProps by lazy {
+      listOf(
+        "android.injected.build.model.v2",
+        "android.injected.build.model.only",
+        "android.injected.build.model.only.advanced",
+      )
+    }
   }
 }
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AggregatedPackagesTransform.kt
similarity index 93%
rename from java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt
rename to java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AggregatedPackagesTransform.kt
index cc9c2bb..ac964bb 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/AggregatedPackagesTransform.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AggregatedPackagesTransform.kt
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
-package dagger.hilt.android.plugin.util
+package dagger.hilt.android.plugin.transform
 
 import dagger.hilt.android.plugin.root.AggregatedAnnotation
+import dagger.hilt.android.plugin.util.forEachZipEntry
+import dagger.hilt.android.plugin.util.isClassFile
+import dagger.hilt.android.plugin.util.isJarFile
+import dagger.hilt.android.plugin.util.walkInPlatformIndependentOrder
 import java.io.ByteArrayOutputStream
 import java.io.File
 import java.util.zip.ZipEntry
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AndroidEntryPointClassVisitor.kt
similarity index 97%
rename from java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
rename to java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AndroidEntryPointClassVisitor.kt
index 16e4af9..d849894 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/AndroidEntryPointClassVisitor.kt
@@ -14,18 +14,13 @@
  * limitations under the License.
  */
 
-package dagger.hilt.android.plugin
+package dagger.hilt.android.plugin.transform
 
 import com.android.build.api.instrumentation.AsmClassVisitorFactory
 import com.android.build.api.instrumentation.ClassContext
 import com.android.build.api.instrumentation.ClassData
 import com.android.build.api.instrumentation.InstrumentationParameters
-import java.io.File
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Internal
-import org.objectweb.asm.ClassReader
 import org.objectweb.asm.ClassVisitor
-import org.objectweb.asm.FieldVisitor
 import org.objectweb.asm.MethodVisitor
 import org.objectweb.asm.Opcodes
 
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/CopyTransform.kt
similarity index 97%
rename from java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
rename to java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/CopyTransform.kt
index f7c33dc..1f9eb89 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/transform/CopyTransform.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package dagger.hilt.android.plugin.util
+package dagger.hilt.android.plugin.transform
 
 import org.gradle.api.artifacts.transform.InputArtifact
 import org.gradle.api.artifacts.transform.TransformAction
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
index a91ce35..0489de7 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
@@ -16,7 +16,10 @@
 
 package dagger.hilt.android.plugin.util
 
-import com.google.devtools.ksp.gradle.KspTaskJvm
+import com.android.build.api.variant.ComponentIdentity
+import com.google.devtools.ksp.gradle.KspAATask
+import com.google.devtools.ksp.gradle.KspTask
+import kotlin.reflect.KClass
 import org.gradle.api.Project
 import org.gradle.api.Task
 import org.gradle.api.tasks.compile.JavaCompile
@@ -25,17 +28,17 @@
 
 internal fun addJavaTaskProcessorOptions(
   project: Project,
-  component: ComponentCompat,
+  variantIdentity: ComponentIdentity,
   produceArgProvider: (Task) -> CommandLineArgumentProvider
-) = project.tasks.withType(JavaCompile::class.java) { task ->
-  if (task.name == "compile${component.name.capitalize()}JavaWithJavac") {
+) = project.tasks.withType(JavaCompile::class.java).configureEach { task ->
+  if (task.name == "compile${variantIdentity.name.capitalize()}JavaWithJavac") {
     task.options.compilerArgumentProviders.add(produceArgProvider.invoke(task))
   }
 }
 
 internal fun addKaptTaskProcessorOptions(
   project: Project,
-  component: ComponentCompat,
+  variantIdentity: ComponentIdentity,
   produceArgProvider: (Task) -> CommandLineArgumentProvider
 ) = project.plugins.withId("kotlin-kapt") {
   checkClass("org.jetbrains.kotlin.gradle.internal.KaptTask") {
@@ -48,10 +51,10 @@
     sub-projects.
     """.trimIndent()
   }
-  project.tasks.withType(KaptTask::class.java) { task ->
-    if (task.name == "kapt${component.name.capitalize()}Kotlin" ||
+  project.tasks.withType(KaptTask::class.java).configureEach { task ->
+    if (task.name == "kapt${variantIdentity.name.capitalize()}Kotlin" ||
         // Task names in shared/src/AndroidMain in KMP projects has a platform suffix.
-        task.name == "kapt${component.name.capitalize()}KotlinAndroid") {
+        task.name == "kapt${variantIdentity.name.capitalize()}KotlinAndroid") {
       val argProvider = produceArgProvider.invoke(task)
       // TODO: Update once KT-58009 is fixed.
       try {
@@ -69,10 +72,10 @@
 
 internal fun addKspTaskProcessorOptions(
   project: Project,
-  component: ComponentCompat,
+  variantIdentity: ComponentIdentity,
   produceArgProvider: (Task) -> CommandLineArgumentProvider
 ) = project.plugins.withId("com.google.devtools.ksp") {
-  checkClass("com.google.devtools.ksp.gradle.KspTaskJvm") {
+  check(kspOneTaskClass != null || kspTwoTaskClass != null) {
     """
     The KSP plugin was detected to be applied but its task class could not be found.
 
@@ -84,13 +87,25 @@
     See https://github.com/google/dagger/issues/3965 for more details.
     """.trimIndent()
   }
-  project.tasks.withType(KspTaskJvm::class.java) { task ->
-    if (task.name == "ksp${component.name.capitalize()}Kotlin" ||
+  fun <T : Task> configureEach(
+    kclass: KClass<T>,
+    block: T.(CommandLineArgumentProvider) -> Unit
+  ) {
+    project.tasks.withType(kclass.java).configureEach { task ->
+      if (task.name == "ksp${variantIdentity.name.capitalize()}Kotlin" ||
         // Task names in shared/src/AndroidMain in KMP projects has a platform suffix.
-        task.name == "ksp${component.name.capitalize()}KotlinAndroid") {
-      task.commandLineArgumentProviders.add(produceArgProvider.invoke(task))
+        task.name == "ksp${variantIdentity.name.capitalize()}KotlinAndroid") {
+        val argProvider = produceArgProvider.invoke(task)
+        task.block(argProvider)
+      }
     }
   }
+  if (kspOneTaskClass != null) {
+    configureEach(KspTask::class) { commandLineArgumentProviders.add(it) }
+  }
+  if (kspTwoTaskClass != null) {
+    configureEach(KspAATask::class) { commandLineArgumentProviders.add(it) }
+  }
 }
 
 private inline fun checkClass(fqn: String, msg: () -> String) {
@@ -101,10 +116,21 @@
   }
 }
 
-internal fun Task.isKspTask(): Boolean = try {
-  val kspTaskClass = Class.forName("com.google.devtools.ksp.gradle.KspTask")
-  kspTaskClass.isAssignableFrom(this::class.java)
-} catch (ex: ClassNotFoundException) {
-  false
-}
+private val kspOneTaskClass =
+  try {
+    Class.forName("com.google.devtools.ksp.gradle.KspTask")
+  } catch (ex: ClassNotFoundException) {
+    null
+  }
+
+private val kspTwoTaskClass =
+  try {
+    Class.forName("com.google.devtools.ksp.gradle.KspAATask")
+  } catch (ex: ClassNotFoundException) {
+    null
+  }
+
+internal fun Task.isKspTask() =
+  kspOneTaskClass?.isAssignableFrom(this::class.java) == true ||
+    kspTwoTaskClass?.isAssignableFrom(this::class.java) == true
 
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Variants.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Variants.kt
new file mode 100644
index 0000000..24a6254
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Variants.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Dagger 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
+ *
+ * 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 dagger.hilt.android.plugin.util
+
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.api.variant.Component
+import com.android.build.api.variant.HasAndroidTest
+import com.android.build.api.variant.HasUnitTest
+import com.android.build.gradle.AppExtension
+import com.android.build.gradle.BaseExtension
+import com.android.build.gradle.LibraryExtension
+import com.android.build.gradle.TestExtension
+
+/**
+ * Invokes the [block] function for each Android variant, including android instrumentation tests
+ * and host unit tests.
+ */
+internal fun AndroidComponentsExtension<*, *, *>.onAllVariants(block: (Component) -> Unit) {
+  this.onVariants { variant ->
+    block(variant)
+    (variant as? HasUnitTest)?.unitTest?.let { block(it) }
+    (variant as? HasAndroidTest)?.androidTest?.let { block(it) }
+  }
+}
+
+/**
+ * Invokes the [block] function for each Android variant that is considered a Hilt root, where
+ * dependencies are aggregated and components are generated.
+ */
+internal fun BaseExtension.forEachRootVariant(
+  @Suppress("DEPRECATION") block: (variant: com.android.build.gradle.api.BaseVariant) -> Unit
+) {
+  when (this) {
+    is AppExtension -> {
+      // For an app project we configure the app variant and both androidTest and unitTest
+      // variants, Hilt components are generated in all of them.
+      applicationVariants.all { block(it) }
+      testVariants.all { block(it) }
+      unitTestVariants.all { block(it) }
+    }
+    is LibraryExtension -> {
+      // For a library project, only the androidTest and unitTest variant are configured since
+      // Hilt components are not generated in a library.
+      testVariants.all { block(it) }
+      unitTestVariants.all { block(it) }
+    }
+    is TestExtension -> {
+      applicationVariants.all { block(it) }
+    }
+    else -> error("Hilt plugin does not know how to configure '$this'")
+  }
+}
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryA/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryA/build.gradle
index 9e8a097..38f62e5 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryA/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryA/build.gradle
@@ -5,7 +5,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 21
@@ -17,6 +17,7 @@
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
     }
+    namespace = "liba"
 }
 
 dependencies {
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryC/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryC/build.gradle
index 450f128..549e008 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryC/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/android-libraryC/build.gradle
@@ -5,7 +5,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 21
@@ -17,6 +17,7 @@
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
     }
+    namespace = "libc"
 }
 
 dependencies {
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/app/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/app/build.gradle
index 954e209..ced9532 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/app/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/app/build.gradle
@@ -21,7 +21,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     flavorDimensions 'api', 'version'
     productFlavors {
@@ -49,6 +49,8 @@
         targetSdkVersion 33
     }
 
+    namespace = "simple.app"
+
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/feature/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/feature/build.gradle
index 068d402..5cfb7ad 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/feature/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/flavored-project/feature/build.gradle
@@ -21,7 +21,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     flavorDimensions 'api', 'version'
     productFlavors {
@@ -48,6 +48,8 @@
         targetSdkVersion 33
     }
 
+    namespace = "simple.library"
+
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/app/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/app/build.gradle
index 506d40a..01ba5b4 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/app/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/app/build.gradle
@@ -29,6 +29,8 @@
         targetSdkVersion 33
     }
 
+    namespace = "simple.app"
+
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/feature/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/feature/build.gradle
index 57f7a74..d9102bd 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/feature/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/simple-project-for-agp-test/feature/build.gradle
@@ -28,6 +28,8 @@
         targetSdkVersion 33
     }
 
+    namespace = "simple.library"
+
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/AGPCompatibilityTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/AGPCompatibilityTest.kt
index f488fb3..e243c3b 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/AGPCompatibilityTest.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/AGPCompatibilityTest.kt
@@ -88,10 +88,7 @@
     fun parameters() =
       listOf(
         // AGP 8.3 requires Gradle 8.4 and JDK 17.
-        arrayOf("8.3.0-alpha11", "8.4"),
-        arrayOf("7.2.0", "7.4.2"),
-        arrayOf("7.1.0", "7.4.2"),
-        arrayOf("7.0.0", "7.4.2"),
+        arrayOf("8.3.0", "8.4"),
       )
   }
 }
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/BuildCacheTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/BuildCacheTest.kt
index c5a67af..85ac371 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/BuildCacheTest.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/BuildCacheTest.kt
@@ -86,7 +86,6 @@
         add(":compressDebugAssets")
         add(":desugarDebugFileDependencies")
         add(":extractDeepLinksDebug")
-        add(":generateDebugBuildConfig")
         add(":generateDebugResValues")
         // When aggregating task is enabled, the plugin adds two more tasks that should be
         // cacheable.
@@ -97,10 +96,14 @@
         add(":javaPreCompileDebug")
         add(":mergeDebugAssets")
         add(":mergeDebugJniLibFolders")
+        add(":mergeDebugResources")
         add(":mergeDebugShaders")
         add(":mergeExtDexDebug")
         add(":mergeLibDexDebug")
         add(":mergeProjectDexDebug")
+        add(":packageDebugResources")
+        add(":parseDebugLocalResources")
+        add(":processDebugMainManifest")
         add(":processDebugManifestForPackage")
         add(":transformDebugClassesWithAsm")
       }
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
index 221dfcf..f7d41f3 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
@@ -157,7 +157,7 @@
 
         android {
           compileSdkVersion 33
-          buildToolsVersion "33.0.0"
+          buildToolsVersion "33.0.1"
 
           defaultConfig {
             ${ if (isAppProject) "applicationId \"plugin.test\"" else "" }
@@ -165,6 +165,8 @@
             targetSdkVersion 33
           }
 
+          namespace = "minimal"
+
           compileOptions {
               sourceCompatibility JavaVersion.VERSION_11
               targetCompatibility JavaVersion.VERSION_11
@@ -254,7 +256,7 @@
     // Finds a transformed file. The srcFilePath is relative to the app's package.
     fun getTransformedFile(srcFilePath: String): File {
       val parentDir =
-        File(projectRoot, "build/intermediates/asm_instrumented_project_classes/debug")
+        File(projectRoot, "build/intermediates/classes/debug/transformDebugClassesWithAsm/dirs")
       return File(parentDir, srcFilePath).also {
         if (!it.exists()) {
           error("Unable to find transformed class ${it.path}")
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
index 4fb25a0..048f237 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
@@ -148,7 +148,7 @@
 
       android {
         compileSdkVersion 33
-        buildToolsVersion "33.0.0"
+        buildToolsVersion "33.0.1"
 
         defaultConfig {
           applicationId "hilt.simple"
@@ -161,6 +161,8 @@
           }
         }
 
+        namespace = "simple"
+
         compileOptions {
             sourceCompatibility JavaVersion.VERSION_11
             targetCompatibility JavaVersion.VERSION_11
@@ -183,7 +185,7 @@
         testImplementation 'junit:junit:4.12'
         testImplementation 'androidx.test.ext:junit:1.1.3'
         testImplementation 'androidx.test:runner:1.4.0'
-        testImplementation 'org.robolectric:robolectric:4.4'
+        testImplementation 'org.robolectric:robolectric:4.11.1'
         testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
         testAnnotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
       }
@@ -244,17 +246,17 @@
     genAppInjectorDeps =
       File(
         projectRoot,
-        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.java"
+        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.java",
       )
     genActivityInjectorDeps1 =
       File(
         projectRoot,
-        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.java"
+        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.java",
       )
     genActivityInjectorDeps2 =
       File(
         projectRoot,
-        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.java"
+        "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.java",
       )
     genModuleDeps1 =
       File(projectRoot, "$defaultGenSrcDir/hilt_aggregated_deps/_simple_Module1.java")
@@ -269,35 +271,35 @@
       File(
         projectRoot,
         testComponentTreeDepsGenSrcDir +
-          "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.java"
+          "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.java",
       )
     genTest2ComponentTreeDeps =
       File(
         projectRoot,
         testComponentTreeDepsGenSrcDir +
-          "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.java"
+          "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.java",
       )
     genTest1HiltComponents =
       File(
         projectRoot,
-        "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.java"
+        "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.java",
       )
     genTest2HiltComponents =
       File(
         projectRoot,
-        "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.java"
+        "$testRootGenSrcDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.java",
       )
     genTest1DaggerHiltApplicationComponent =
       File(
         projectRoot,
         testRootGenSrcDir +
-          "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.java"
+          "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.java",
       )
     genTest2DaggerHiltApplicationComponent =
       File(
         projectRoot,
         testRootGenSrcDir +
-          "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.java"
+          "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.java",
       )
 
     classSrcApp = File(projectRoot, "$defaultClassesDir/simple/SimpleApp.class")
@@ -319,17 +321,17 @@
     classGenAppInjectorDeps =
       File(
         projectRoot,
-        "$defaultClassesDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.class"
+        "$defaultClassesDir/hilt_aggregated_deps/_simple_SimpleApp_GeneratedInjector.class",
       )
     classGenActivityInjectorDeps1 =
       File(
         projectRoot,
-        "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.class"
+        "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity1_GeneratedInjector.class",
       )
     classGenActivityInjectorDeps2 =
       File(
         projectRoot,
-        "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.class"
+        "$defaultClassesDir/hilt_aggregated_deps/_simple_Activity2_GeneratedInjector.class",
       )
     classGenModuleDeps1 =
       File(projectRoot, "$defaultClassesDir/hilt_aggregated_deps/_simple_Module1.class")
@@ -345,35 +347,35 @@
       File(
         projectRoot,
         testRootClassesDir +
-          "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.class"
+          "/dagger/hilt/android/internal/testing/root/Test1_ComponentTreeDeps.class",
       )
     classGenTest2ComponentTreeDeps =
       File(
         projectRoot,
         testRootClassesDir +
-          "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.class"
+          "/dagger/hilt/android/internal/testing/root/Test2_ComponentTreeDeps.class",
       )
     classGenTest1HiltComponents =
       File(
         projectRoot,
-        "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.class"
+        "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test1_HiltComponents.class",
       )
     classGenTest2HiltComponents =
       File(
         projectRoot,
-        "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.class"
+        "$testRootClassesDir/dagger/hilt/android/internal/testing/root/Test2_HiltComponents.class",
       )
     classGenTest1DaggerHiltApplicationComponent =
       File(
         projectRoot,
         testRootClassesDir +
-          "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.class"
+          "/dagger/hilt/android/internal/testing/root/DaggerTest1_HiltComponents_SingletonC.class",
       )
     classGenTest2DaggerHiltApplicationComponent =
       File(
         projectRoot,
         testRootClassesDir +
-          "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.class"
+          "/dagger/hilt/android/internal/testing/root/DaggerTest2_HiltComponents_SingletonC.class",
       )
   }
 
@@ -400,7 +402,7 @@
         genModuleDeps2,
         genComponentTreeDeps,
         genHiltComponents,
-        genDaggerHiltApplicationComponent
+        genDaggerHiltApplicationComponent,
       )
     )
 
@@ -425,7 +427,7 @@
         classGenModuleDeps2,
         classGenComponentTreeDeps,
         classGenHiltComponents,
-        classGenDaggerHiltApplicationComponent
+        classGenDaggerHiltApplicationComponent,
       )
     )
   }
@@ -445,7 +447,7 @@
         super.onResume();
       }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalBuild()
@@ -464,7 +466,7 @@
           genActivityInjector1,
           genActivityInjectorDeps1,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       } else {
         // * Root classes along with components are always re-generated (aggregated processor)
@@ -477,7 +479,7 @@
           genActivityInjectorDeps1,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -513,7 +515,7 @@
           classGenActivityInjectorDeps1,
           classGenHiltComponents,
           classGenComponentTreeDeps,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -531,7 +533,7 @@
       """
       private void foo() { }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalBuild()
@@ -550,11 +552,7 @@
       if (incapMode == ISOLATING_MODE) {
         // * Aggregating task did not run, no change in deps
         expect.that(result.task(aggregatingTaskName)!!.outcome).isEqualTo(TaskOutcome.UP_TO_DATE)
-        listOf(
-          genHiltActivity1,
-          genActivityInjector1,
-          genActivityInjectorDeps1,
-        )
+        listOf(genHiltActivity1, genActivityInjector1, genActivityInjectorDeps1)
       } else {
         // * Root classes along with components are always re-generated (aggregated processor)
         listOf(
@@ -566,7 +564,7 @@
           genActivityInjectorDeps1,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -585,7 +583,7 @@
           classSrcActivity1,
           classGenHiltActivity1,
           classGenActivityInjector1,
-          classGenActivityInjectorDeps1
+          classGenActivityInjectorDeps1,
         )
       } else {
         // * All aggregating processor gen sources are re-compiled
@@ -599,7 +597,7 @@
           classGenActivityInjectorDeps1,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -620,7 +618,7 @@
         return 10.10;
       }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalBuild()
@@ -637,7 +635,7 @@
           genHiltApp, // Re-generated because components got re-generated
           genModuleDeps1,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       } else {
         // * Root classes along with components are always re-generated (aggregated processor)
@@ -648,7 +646,7 @@
           genModuleDeps1,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -668,7 +666,7 @@
           classGenHiltApp,
           classGenModuleDeps1,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       } else {
         // * All aggregating processor gen sources are re-compiled
@@ -680,7 +678,7 @@
           classGenModuleDeps1,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -701,7 +699,7 @@
         super.onCreate();
       }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalBuild()
@@ -719,7 +717,7 @@
           genAppInjector,
           genAppInjectorDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       } else {
         // * Root classes along with components are always re-generated (aggregated processor)
@@ -729,7 +727,7 @@
           genAppInjectorDeps,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -749,7 +747,7 @@
           classGenAppInjector,
           classGenAppInjectorDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       } else {
         // * All aggregating processor gen sources are re-compiled
@@ -760,7 +758,7 @@
           classGenAppInjectorDeps,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -789,7 +787,7 @@
           genHiltApp, // Re-generated because components got re-generated
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       } else {
         listOf(
@@ -798,7 +796,7 @@
           genAppInjectorDeps,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -811,7 +809,7 @@
         classSrcActivity2,
         classGenHiltActivity2,
         classGenActivityInjector2,
-        classGenActivityInjectorDeps2
+        classGenActivityInjectorDeps2,
       )
     )
     val recompiledClassFiles =
@@ -820,7 +818,7 @@
           classGenHiltApp,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       } else {
         listOf(
@@ -829,7 +827,7 @@
           classGenAppInjectorDeps,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -858,7 +856,7 @@
           genHiltApp, // Re-generated because components got re-generated
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       } else {
         // * Root classes along with components are always re-generated (aggregated processor)
@@ -868,7 +866,7 @@
           genAppInjectorDeps,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -883,7 +881,7 @@
           classGenHiltApp,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       } else {
         listOf(
@@ -892,7 +890,7 @@
           classGenAppInjectorDeps,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -936,7 +934,7 @@
           genAppInjectorDeps,
           genComponentTreeDeps,
           genHiltComponents,
-          genDaggerHiltApplicationComponent
+          genDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.JAVA, regeneratedSourceFiles)
@@ -951,7 +949,7 @@
           classGenAppInjectorDeps,
           classGenComponentTreeDeps,
           classGenHiltComponents,
-          classGenDaggerHiltApplicationComponent
+          classGenDaggerHiltApplicationComponent,
         )
       }
     assertChangedFiles(FileType.CLASS, recompiledClassFiles)
@@ -1001,7 +999,7 @@
       @Test
       public void newTest() { }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalTestBuild()
@@ -1012,10 +1010,7 @@
 
     val regeneratedSourceFiles =
       if (incapMode == ISOLATING_MODE) {
-        listOf(
-          genTest1HiltComponents,
-          genTest1DaggerHiltApplicationComponent,
-        )
+        listOf(genTest1HiltComponents, genTest1DaggerHiltApplicationComponent)
       } else {
         listOf(
           genTest1ComponentTreeDeps,
@@ -1073,7 +1068,7 @@
       """
       private void newMethod() { }
       """
-        .trimIndent()
+        .trimIndent(),
     )
 
     val result = runIncrementalTestBuild()
diff --git a/java/dagger/hilt/android/plugin/settings.gradle b/java/dagger/hilt/android/plugin/settings.gradle
index 778bf22..4060e34 100644
--- a/java/dagger/hilt/android/plugin/settings.gradle
+++ b/java/dagger/hilt/android/plugin/settings.gradle
@@ -16,9 +16,3 @@
 
 rootProject.name = 'hilt-gradle-plugin'
 include ':main'
-include ':agp-wrapper'
-include ':agp-wrapper-impl'
-include ':agp-wrapper-7-0'
-include ':agp-wrapper-7-1'
-include ':agp-wrapper-7-2'
-
diff --git a/java/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/processor/BUILD
index bf5a6c3..4e4357e 100644
--- a/java/dagger/hilt/android/processor/BUILD
+++ b/java/dagger/hilt/android/processor/BUILD
@@ -15,8 +15,9 @@
 # Description:
 #   Hilt android processors.
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "POM_VERSION")
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -92,7 +93,7 @@
         "net.ltgt.gradle.incap:incap",
         "org.jetbrains.kotlin:kotlin-stdlib",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_root_packages = [
         # Java 11 javadocs requires non-empty root package so use ".internal" as the root package.
         "dagger.hilt.processor.internal",
diff --git a/java/dagger/hilt/android/processor/internal/BUILD b/java/dagger/hilt/android/processor/internal/BUILD
index 45615e4..60698ad 100644
--- a/java/dagger/hilt/android/processor/internal/BUILD
+++ b/java/dagger/hilt/android/processor/internal/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Internal code for implementing Hilt android processors.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
index e1bf74f..dfee51a 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
@@ -95,7 +95,8 @@
       Generators.copyConstructors(
           metadata.baseElement(),
           CodeBlock.builder().addStatement("_initHiltInternal()").build(),
-          builder);
+          builder,
+          metadata.element());
       builder.addMethod(init());
       if (!metadata.overridesAndroidEntryPointClass()) {
         builder
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index 327412b..aef29e5 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -14,6 +14,8 @@
 # Description:
 #   Hilt android processors.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
index 78a7976..d2005ac 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
@@ -78,7 +78,7 @@
     JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
     Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
     Processors.addGeneratedAnnotation(builder, env, getClass());
-    Generators.copyConstructors(metadata.baseElement(), builder);
+    Generators.copyConstructors(metadata.baseElement(), builder, metadata.element());
 
     metadata.baseElement().getTypeParameters().stream()
         .map(XTypeParameterElement::getTypeVariableName)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
index 45017e4..873e654 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
@@ -86,7 +86,7 @@
     Processors.addGeneratedAnnotation(builder, env, getClass());
     Generators.copyLintAnnotations(metadata.element(), builder);
     Generators.copySuppressAnnotations(metadata.element(), builder);
-    Generators.copyConstructors(metadata.baseElement(), builder);
+    Generators.copyConstructors(metadata.baseElement(), builder, metadata.element());
 
     metadata.baseElement().getTypeParameters().stream()
         .map(XTypeParameterElement::getTypeVariableName)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
index dc2339b..6213a4a 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
@@ -28,6 +28,7 @@
 import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XConstructorElement;
 import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
 import androidx.room.compiler.processing.XVariableElement;
 import com.google.common.base.Preconditions;
@@ -45,6 +46,7 @@
 import dagger.hilt.android.processor.internal.AndroidClassNames;
 import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata.AndroidType;
 import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.Processors;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
@@ -65,15 +67,20 @@
   }
 
   /** Copies all constructors with arguments to the builder. */
-  static void copyConstructors(XTypeElement baseClass, TypeSpec.Builder builder) {
-    copyConstructors(baseClass, CodeBlock.builder().build(), builder);
+  static void copyConstructors(
+      XTypeElement baseClass, TypeSpec.Builder builder, XTypeElement subclassReference) {
+    copyConstructors(baseClass, CodeBlock.builder().build(), builder, subclassReference);
   }
 
   /** Copies all constructors with arguments along with an appended body to the builder. */
-  static void copyConstructors(XTypeElement baseClass, CodeBlock body, TypeSpec.Builder builder) {
+  static void copyConstructors(
+      XTypeElement baseClass,
+      CodeBlock body,
+      TypeSpec.Builder builder,
+      XTypeElement subclassReference) {
     ImmutableList<XConstructorElement> constructors =
         baseClass.getConstructors().stream()
-            .filter(constructor -> !constructor.isPrivate())
+            .filter(constructor -> isConstructorVisibleToSubclass(constructor, subclassReference))
             .collect(toImmutableList());
 
     if (constructors.size() == 1
@@ -86,6 +93,30 @@
     constructors.forEach(constructor -> builder.addMethod(copyConstructor(constructor, body)));
   }
 
+  /**
+   * Returns true if the constructor is visibile to a subclass in the same package as the reference.
+   * A reference is used because usually for generators the subclass is being generated and so
+   * doesn't actually exist.
+   */
+  static boolean isConstructorVisibleToSubclass(
+      XConstructorElement constructor, XTypeElement subclassReference) {
+    // Check if the constructor has package private visibility and we're outside the package
+    if (Processors.hasJavaPackagePrivateVisibility(constructor)
+        && !constructor
+            .getEnclosingElement()
+            .getPackageName()
+            .contentEquals(subclassReference.getPackageName())) {
+      return false;
+      // Or if it is private, we know generated code can't be in the same file
+    } else if (constructor.isPrivate()) {
+      return false;
+    }
+
+    // Assume this is for a subclass per the name, so both protected and public methods are always
+    // accessible.
+    return true;
+  }
+
   /** Returns Optional with AnnotationSpec for Nullable if found on element, empty otherwise. */
   private static Optional<AnnotationSpec> getNullableAnnotationSpec(XElement element) {
     for (XAnnotation annotation : element.getAllAnnotations()) {
@@ -100,14 +131,30 @@
     return Optional.empty();
   }
 
+  /** Returns a TypeName for the given type, including any @Nullable annotations on it. */
+  private static TypeName withAnyNullnessAnnotation(XType type) {
+    for (XAnnotation annotation : type.getAllAnnotations()) {
+      if (annotation.getClassName().simpleName().contentEquals("Nullable")) {
+        return type.getTypeName().annotated(toAnnotationSpec(annotation));
+      }
+    }
+    return type.getTypeName();
+  }
+
   /**
-   * Returns a ParameterSpec of the input parameter, @Nullable annotated if existing in original
-   * (this does not handle Nullable type annotations).
+   * Returns a ParameterSpec of the input parameter, @Nullable annotated if existing in original.
    */
   private static ParameterSpec getParameterSpecWithNullable(XVariableElement parameter) {
-    ParameterSpec.Builder builder =
-        ParameterSpec.builder(parameter.getType().getTypeName(), getSimpleName(parameter));
-    getNullableAnnotationSpec(parameter).ifPresent(builder::addAnnotation);
+    TypeName type = withAnyNullnessAnnotation(parameter.getType());
+    ParameterSpec.Builder builder = ParameterSpec.builder(type, getSimpleName(parameter));
+    /*
+     * If we already have a type-use Nullable, don't consider also adding a declaration Nullable,
+     * which could be a duplicate in the case of "hybrid" annotations that support both type-use and
+     * declaration targets.
+     */
+    if (!type.isAnnotated()) {
+      getNullableAnnotationSpec(parameter).ifPresent(builder::addAnnotation);
+    }
     return builder.build();
   }
 
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
index 8e1405e..7c63152 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
@@ -16,21 +16,14 @@
 
 package dagger.hilt.android.processor.internal.androidentrypoint;
 
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static java.util.stream.Collectors.joining;
 
 import androidx.room.compiler.processing.JavaPoetExtKt;
-import androidx.room.compiler.processing.XConstructorElement;
-import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XFiler;
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XTypeParameterElement;
-import com.google.common.collect.ImmutableList;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.JavaFile;
 import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeSpec;
 import dagger.hilt.android.processor.internal.AndroidClassNames;
 import dagger.hilt.processor.internal.Processors;
@@ -58,7 +51,6 @@
         TypeSpec.classBuilder(generatedClassName.simpleName())
             .superclass(metadata.baseClassName())
             .addModifiers(metadata.generatedClassModifiers())
-            .addMethods(baseClassConstructors())
             .addMethod(onCreateMethod());
 
     JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
@@ -74,6 +66,7 @@
     Generators.addInjectionMethods(metadata, builder);
 
     Generators.addComponentOverride(metadata, builder);
+    Generators.copyConstructors(metadata.baseElement(), builder, metadata.element());
 
     env.getFiler()
         .write(
@@ -81,29 +74,6 @@
             XFiler.Mode.Isolating);
   }
 
-  private ImmutableList<MethodSpec> baseClassConstructors() {
-    return metadata.baseElement().getConstructors().stream()
-        .map(ServiceGenerator::toMethodSpec)
-        .collect(toImmutableList());
-  }
-
-  private static MethodSpec toMethodSpec(XConstructorElement constructor) {
-    ImmutableList<ParameterSpec> params =
-        constructor.getParameters().stream()
-            .map(ServiceGenerator::toParameterSpec)
-            .collect(toImmutableList());
-
-    return MethodSpec.constructorBuilder()
-        .addParameters(params)
-        .addStatement("super($L)", params.stream().map(p -> p.name).collect(joining(",")))
-        .build();
-  }
-
-  private static ParameterSpec toParameterSpec(XExecutableParameterElement parameter) {
-    return ParameterSpec.builder(parameter.getType().getTypeName(), getSimpleName(parameter))
-        .build();
-  }
-
   // @CallSuper
   // @Override
   // protected void onCreate() {
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
index 799ba1f..d9a09fd 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
@@ -78,7 +78,8 @@
     Generators.addInjectionMethods(metadata, builder);
 
     metadata.baseElement().getConstructors().stream()
-        .filter(this::isConstructorVisibleToGeneratedClass)
+        .filter(constructor -> Generators.isConstructorVisibleToSubclass(
+            constructor, metadata.element()))
         .map(this::constructorMethod)
         .forEach(builder::addMethod);
 
@@ -88,17 +89,6 @@
             XFiler.Mode.Isolating);
   }
 
-  private boolean isConstructorVisibleToGeneratedClass(XConstructorElement constructor) {
-    if (Processors.hasJavaPackagePrivateVisibility(constructor) && !isInOurPackage(constructor)) {
-      return false;
-    } else if (constructor.isPrivate()) {
-      return false;
-    }
-
-    // We extend the base class, so both protected and public methods are always accessible.
-    return true;
-  }
-
   /**
    * Returns a pass-through constructor matching the base class's provided constructorElement. The
    * generated constructor simply calls super(), then inject().
@@ -108,7 +98,9 @@
    * <pre>
    *   Hilt_$CLASS(Context context, ...) {
    *     super(context, ...);
-   *     inject();
+   *     if (!isInEditMode()) {
+   *       inject();
+   *     }
    *   }
    * </pre>
    */
@@ -126,7 +118,9 @@
           AnnotationSpec.builder(AndroidClassNames.TARGET_API).addMember("value", "21").build());
     }
 
-    builder.addStatement("inject()");
+    builder.beginControlFlow("if(!isInEditMode())")
+        .addStatement("inject()")
+        .endControlFlow();
 
     return builder.build();
   }
@@ -185,11 +179,4 @@
     return isDeclared(type)
         && Processors.isAssignableFrom(type.getTypeElement(), AndroidClassNames.CONTEXT);
   }
-
-  private boolean isInOurPackage(XConstructorElement constructor) {
-    return constructor
-        .getEnclosingElement()
-        .getPackageName()
-        .contentEquals(metadata.element().getPackageName());
-  }
 }
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
index 5fb1736..5918b22 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
@@ -14,6 +14,8 @@
 # Description:
 #   Hilt android library for binding values in test processors.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index a4fa94b..339a7a0 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.android.testing.CustomTestApplication.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
index 90760ea..6c01d3c 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -14,7 +14,8 @@
 
 # Description:
 #   ViewModelInject processor.
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_plugin")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
index 920410a..a84c1a4 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
@@ -108,7 +108,8 @@
         val assistedFactoryMethodType = assistedFactoryMethod!!.asMemberOf(assistedFactoryType)
 
         ProcessorErrors.checkState(
-          assistedFactoryMethodType.returnType.asTypeName() == viewModelElement.asClassName(),
+          assistedFactoryMethodType.returnType.asTypeName()
+              .equalsIgnoreNullability(viewModelElement.asClassName()),
           assistedFactoryMethod,
           "Class %s must have a factory method that returns a %s. Found %s.",
           XElements.toStableString(assistedFactory),
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
index 69094c9..9983a98 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
@@ -48,9 +48,14 @@
 class ViewModelValidationPlugin : BindingGraphPlugin {
 
   private lateinit var env: XProcessingEnv
+  private lateinit var daggerProcessingEnv: DaggerProcessingEnv
 
   override fun init(processingEnv: DaggerProcessingEnv, options: MutableMap<String, String>) {
-    env = processingEnv.toXProcessingEnv()
+    daggerProcessingEnv = processingEnv
+  }
+
+  override fun onProcessingRoundBegin() {
+    env = daggerProcessingEnv.toXProcessingEnv()
   }
 
   override fun visitGraph(bindingGraph: BindingGraph, diagnosticReporter: DiagnosticReporter) {
@@ -75,7 +80,7 @@
           "\nInjection of an @HiltViewModel class is prohibited since it does not create a " +
             "ViewModel instance correctly.\nAccess the ViewModel via the Android APIs " +
             "(e.g. ViewModelProvider) instead." +
-            "\nInjected ViewModel: ${target.key().type()}\n"
+            "\nInjected ViewModel: ${target.key().type()}\n",
         )
       } else if (
         isViewModelAssistedFactory(target) && !isInternalViewModelAssistedFactoryUsage(source)
@@ -86,7 +91,7 @@
           "\nInjection of an assisted factory for Hilt ViewModel is prohibited since it " +
             "can not be used to create a ViewModel instance correctly.\nAccess the ViewModel via " +
             "the Android APIs (e.g. ViewModelProvider) instead." +
-            "\nInjected factory: ${target.key().type()}\n"
+            "\nInjected factory: ${target.key().type()}\n",
         )
       }
     }
diff --git a/java/dagger/hilt/android/qualifiers/BUILD b/java/dagger/hilt/android/qualifiers/BUILD
index 51bb842..1b45e9e 100644
--- a/java/dagger/hilt/android/qualifiers/BUILD
+++ b/java/dagger/hilt/android/qualifiers/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Hilt Android qualifiers
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 android_library(
diff --git a/java/dagger/hilt/android/scopes/BUILD b/java/dagger/hilt/android/scopes/BUILD
index d89176f..bf41296 100644
--- a/java/dagger/hilt/android/scopes/BUILD
+++ b/java/dagger/hilt/android/scopes/BUILD
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 # Description:
diff --git a/java/dagger/hilt/android/testing/BUILD b/java/dagger/hilt/android/testing/BUILD
index ee3d78a..ac05b99 100644
--- a/java/dagger/hilt/android/testing/BUILD
+++ b/java/dagger/hilt/android/testing/BUILD
@@ -14,8 +14,9 @@
 # Description:
 #   Testing libraries for Hilt Android.
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "POM_VERSION")
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -248,7 +249,7 @@
         "com.google.guava:guava",
         "javax.annotation:javax.annotation-api",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_exclude_packages = [
         "dagger.hilt.internal",
         "dagger.hilt.android.internal",
diff --git a/java/dagger/hilt/android/testing/compile/BUILD b/java/dagger/hilt/android/testing/compile/BUILD
index 7d41e0d..9959fac 100644
--- a/java/dagger/hilt/android/testing/compile/BUILD
+++ b/java/dagger/hilt/android/testing/compile/BUILD
@@ -14,6 +14,8 @@
 # Description:
 #   Tests for internal code for implementing Hilt processors.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
index 89bf678..39e90a9 100644
--- a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
+++ b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
@@ -70,6 +70,14 @@
 
 /** {@link Compiler} instances for testing Android Hilt. */
 public final class HiltCompilerTests {
+  private static final ImmutableList<String> DEFAULT_JAVAC_OPTIONS = ImmutableList.of();
+
+  private static final ImmutableList<String> DEFAULT_KOTLINC_OPTIONS =
+      ImmutableList.of(
+          "-api-version=1.9",
+          "-language-version=1.9",
+          "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true");
+
   /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */
   public static XProcessingEnv.Backend backend(CompilationResultSubject subject) {
     return CompilerTests.backend(subject);
@@ -161,8 +169,8 @@
                 sources,
                 /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
                 /* inheritClasspath= */ false,
-                /* javacArguments= */ ImmutableList.of(),
-                /* kotlincArguments= */ ImmutableList.of(),
+                /* javacArguments= */ DEFAULT_JAVAC_OPTIONS,
+                /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS,
                 /* kaptProcessors= */ ImmutableList.<Processor>builder()
                     .addAll(defaultProcessors())
                     .addAll(additionalProcessors)
@@ -182,10 +190,10 @@
         new CustomTestApplicationProcessor(),
         new DefineComponentProcessor(),
         new EarlyEntryPointProcessor(),
+        new UninstallModulesProcessor(),
         new GeneratesRootInputProcessor(),
         new OriginatingElementProcessor(),
-        new RootProcessor(),
-        new UninstallModulesProcessor());
+        new RootProcessor());
   }
 
   private static ImmutableList<SymbolProcessorProvider> kspDefaultProcessors() {
@@ -199,10 +207,10 @@
         new KspCustomTestApplicationProcessor.Provider(),
         new KspDefineComponentProcessor.Provider(),
         new KspEarlyEntryPointProcessor.Provider(),
+        new KspUninstallModulesProcessor.Provider(),
         new KspGeneratesRootInputProcessor.Provider(),
         new KspOriginatingElementProcessor.Provider(),
-        new KspRootProcessor.Provider(),
-        new KspUninstallModulesProcessor.Provider());
+        new KspRootProcessor.Provider());
   }
 
   /** Used to compile Hilt sources and inspect the compiled results. */
@@ -274,9 +282,12 @@
           sources().asList(),
           /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
           /* options= */ processorOptions(),
-          /* javacArguments= */ javacArguments().asList(),
-          /* kotlincArguments= */ ImmutableList.of(
-              "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"),
+          /* javacArguments= */
+          ImmutableList.<String>builder()
+              .addAll(DEFAULT_JAVAC_OPTIONS)
+              .addAll(javacArguments())
+              .build(),
+          /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS,
           /* config= */ HiltProcessingEnvConfigs.CONFIGS,
           /* javacProcessors= */ ImmutableList.<Processor>builder()
               .addAll(mergeProcessors(defaultProcessors(), additionalJavacProcessors()))
diff --git a/java/dagger/hilt/codegen/BUILD b/java/dagger/hilt/codegen/BUILD
index c88182b..da19bc2 100644
--- a/java/dagger/hilt/codegen/BUILD
+++ b/java/dagger/hilt/codegen/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   This package contains sources used within code generated sources.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/components/BUILD b/java/dagger/hilt/components/BUILD
index 9baf476..e3fd3b7 100644
--- a/java/dagger/hilt/components/BUILD
+++ b/java/dagger/hilt/components/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Hilt components
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/BUILD b/java/dagger/hilt/internal/BUILD
index ad4dbb5..d199bf2 100644
--- a/java/dagger/hilt/internal/BUILD
+++ b/java/dagger/hilt/internal/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Internal Hilt libraries
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
@@ -41,8 +43,8 @@
         "GeneratedComponentManagerHolder.java",
     ],
     exports = [
-        ":preconditions",
-        ":unsafe_casts",
+        "//java/dagger/hilt/internal:preconditions",
+        "//java/dagger/hilt/internal:unsafe_casts",
     ],
 )
 
diff --git a/java/dagger/hilt/internal/aggregatedroot/BUILD b/java/dagger/hilt/internal/aggregatedroot/BUILD
index 0a7263a..9a8afeb 100644
--- a/java/dagger/hilt/internal/aggregatedroot/BUILD
+++ b/java/dagger/hilt/internal/aggregatedroot/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotation for aggregating information about Hilt roots.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/aliasof/BUILD b/java/dagger/hilt/internal/aliasof/BUILD
index 13d4364..9bbad4d 100644
--- a/java/dagger/hilt/internal/aliasof/BUILD
+++ b/java/dagger/hilt/internal/aliasof/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotation for classes generated by @AliasOf.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/componenttreedeps/BUILD b/java/dagger/hilt/internal/componenttreedeps/BUILD
index 1a100d5..ccc6086 100644
--- a/java/dagger/hilt/internal/componenttreedeps/BUILD
+++ b/java/dagger/hilt/internal/componenttreedeps/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotation for aggregating information about Hilt roots.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/definecomponent/BUILD b/java/dagger/hilt/internal/definecomponent/BUILD
index 973b7cb..1ce3a21 100644
--- a/java/dagger/hilt/internal/definecomponent/BUILD
+++ b/java/dagger/hilt/internal/definecomponent/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotations for classes generated by @DefineComponent and @DefineComponent.Factory.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/generatesrootinput/BUILD b/java/dagger/hilt/internal/generatesrootinput/BUILD
index 8e54ac4..f524499 100644
--- a/java/dagger/hilt/internal/generatesrootinput/BUILD
+++ b/java/dagger/hilt/internal/generatesrootinput/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotations for classes generated by @GeneratesRootInput.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/internal/processedrootsentinel/BUILD b/java/dagger/hilt/internal/processedrootsentinel/BUILD
index 70b72a6..cbcc3e2 100644
--- a/java/dagger/hilt/internal/processedrootsentinel/BUILD
+++ b/java/dagger/hilt/internal/processedrootsentinel/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   The annotation for aggregating information about processed Hilt roots.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/migration/BUILD b/java/dagger/hilt/migration/BUILD
index 27f472a..7d8ed6c 100644
--- a/java/dagger/hilt/migration/BUILD
+++ b/java/dagger/hilt/migration/BUILD
@@ -14,6 +14,8 @@
 # Description:
 #   Libraries for migration.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD
index ecbc294..4e90e76 100644
--- a/java/dagger/hilt/processor/BUILD
+++ b/java/dagger/hilt/processor/BUILD
@@ -15,8 +15,9 @@
 # Description:
 #   Hilt android processors.
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "POM_VERSION")
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -114,7 +115,7 @@
         "net.ltgt.gradle.incap:incap",
         "org.jetbrains.kotlin:kotlin-stdlib",
     ],
-    javadoc_android_api_level = 32,
+    javadoc_android_api_level = 34,
     javadoc_root_packages = [
         # Java 11 javadocs requires non-empty root package so use ".internal" as the root package.
         "dagger.hilt.processor.internal",
diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD
index 8828227..cd83d83 100644
--- a/java/dagger/hilt/processor/internal/BUILD
+++ b/java/dagger/hilt/processor/internal/BUILD
@@ -15,7 +15,8 @@
 # Description:
 #   Internal code for implementing Hilt processors.
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_library")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
index 840ba9c..0caaf7b 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
@@ -107,8 +107,11 @@
   }
 
   private static AggregatedDepsMetadata create(XTypeElement element, XProcessingEnv env) {
+    checkState(
+        element.hasAnnotation(ClassNames.AGGREGATED_DEPS),
+        "Missing @AggregatedDeps annotation on %s",
+        element.getClassName().canonicalName());
     XAnnotation annotation = element.getAnnotation(ClassNames.AGGREGATED_DEPS);
-
     return new AutoValue_AggregatedDepsMetadata(
         element,
         getTestElement(annotation.getAnnotationValue("test"), env),
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
index 2d1bd92..f69d509 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor that aggregates metadata about Hilt @InstallIn annotations
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 # TODO(bcorso): Remove all AggregatedDeps usage from the processor class path.
diff --git a/java/dagger/hilt/processor/internal/aliasof/BUILD b/java/dagger/hilt/processor/internal/aliasof/BUILD
index 3c72e71..47776ec 100644
--- a/java/dagger/hilt/processor/internal/aliasof/BUILD
+++ b/java/dagger/hilt/processor/internal/aliasof/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.AliasOfProcessor.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/definecomponent/BUILD b/java/dagger/hilt/processor/internal/definecomponent/BUILD
index a259b72..4cf5f46 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/BUILD
+++ b/java/dagger/hilt/processor/internal/definecomponent/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.DefineComponent.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
index b9caf58..766752a 100644
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.AliasOfProcessor.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
index 81607e9..c371e8d 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.android.EarlyEntryPoint.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
index afd611f..39c05b6 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.GeneratesRootInput.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/kotlin/BUILD b/java/dagger/hilt/processor/internal/kotlin/BUILD
index 437ea0f..32343ab 100644
--- a/java/dagger/hilt/processor/internal/kotlin/BUILD
+++ b/java/dagger/hilt/processor/internal/kotlin/BUILD
@@ -15,13 +15,16 @@
 # Description:
 #   Sources related to Kotlin metadata.
 
-load("@rules_java//java:defs.bzl", "java_library")
+load("//tools:bazel_compat.bzl", "compat_kt_jvm_library")
 
 package(default_visibility = ["//:src"])
 
-java_library(
+compat_kt_jvm_library(
     name = "kotlin",
-    srcs = glob(["*.java"]),
+    srcs = glob([
+        "*.java",
+        "*.kt",
+    ]),
     deps = [
         "//:dagger_with_compiler",
         "//java/dagger/hilt/processor/internal:classnames",
@@ -33,7 +36,7 @@
         "//third_party/java/javapoet",
         "//third_party/java/jsr305_annotations",
         "//third_party/java/jsr330_inject",
+        "//third_party/kotlin/kotlin_metadata_jvm",
         "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
-        "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
     ],
 )
diff --git a/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt b/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt
new file mode 100644
index 0000000..d8ec6bd
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/kotlin/ClassMetadata.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Dagger 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
+ *
+ * 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 dagger.hilt.processor.internal.kotlin
+
+import androidx.room.compiler.processing.XAnnotation
+import androidx.room.compiler.processing.XFieldElement
+import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XTypeElement
+import kotlin.Metadata
+import kotlin.metadata.declaresDefaultValue
+import kotlin.metadata.KmClass
+import kotlin.metadata.KmConstructor
+import kotlin.metadata.KmFunction
+import kotlin.metadata.KmProperty
+import kotlin.metadata.KmValueParameter
+import kotlin.metadata.jvm.KotlinClassMetadata
+import kotlin.metadata.jvm.fieldSignature
+import kotlin.metadata.jvm.getterSignature
+import kotlin.metadata.jvm.signature
+import kotlin.metadata.jvm.syntheticMethodForAnnotations
+
+/** Container classes for kotlin metadata types. */
+class ClassMetadata private constructor(private val kmClass: KmClass) {
+  val functionsBySignature = buildList<FunctionMetadata> {
+    addAll(kmClass.constructors.map { ConstructorMetadata(it) })
+    addAll(kmClass.functions.map { MethodMetadata(it) })
+  }.associateBy { it.signature }
+
+  val propertiesBySignature =
+      kmClass.properties
+          .filter { it.fieldSignature != null }
+          .map { PropertyMetadata(it) }
+          .associateBy { it.fieldSignature }
+
+  fun constructors(): List<FunctionMetadata> =
+      functionsBySignature.values.filterIsInstance<ConstructorMetadata>()
+
+  companion object {
+    /** Parse Kotlin class metadata from a given type element. */
+    @JvmStatic
+    fun of(typeElement: XTypeElement): ClassMetadata {
+      val metadataAnnotation = checkNotNull(typeElement.getAnnotation(Metadata::class)).value
+      return when (val classMetadata = KotlinClassMetadata.readStrict(metadataAnnotation)) {
+        is KotlinClassMetadata.Class -> ClassMetadata(classMetadata.kmClass)
+        else -> error("Unsupported metadata type: ${classMetadata}")
+      }
+    }
+  }
+}
+
+class ConstructorMetadata(private val kmConstructor: KmConstructor) : FunctionMetadata {
+  override val name = "<init>"
+  override val signature = kmConstructor.signature!!.toString()
+  override val parameters = kmConstructor.valueParameters.map { ParameterMetadata(it) }
+}
+
+class MethodMetadata(private val kmFunction: KmFunction) : FunctionMetadata {
+  override val name = kmFunction.name
+  override val signature = kmFunction.signature!!.toString()
+  override val parameters = kmFunction.valueParameters.map { ParameterMetadata(it) }
+}
+
+interface FunctionMetadata {
+  val name: String
+  val signature: String
+  val parameters: List<ParameterMetadata>
+}
+
+class PropertyMetadata(private val kmProperty: KmProperty) {
+  val name = kmProperty.name
+
+  /** Returns the JVM field descriptor of the backing field of this property. */
+  val fieldSignature = kmProperty.fieldSignature?.toString()
+
+  val getterSignature = kmProperty.getterSignature?.toString()
+
+  /** Returns JVM method descriptor of the synthetic method for property annotations. */
+  val methodForAnnotationsSignature = kmProperty.syntheticMethodForAnnotations?.toString()
+}
+
+class ParameterMetadata(private val kmValueParameter: KmValueParameter) {
+  val name = kmValueParameter.name
+
+  fun declaresDefaultValue() = kmValueParameter.declaresDefaultValue
+}
+
diff --git a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
index e98b2b3..47edf6e 100644
--- a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
+++ b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
@@ -17,37 +17,20 @@
 package dagger.hilt.processor.internal.kotlin;
 
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static kotlinx.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE;
 
-import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XFieldElement;
 import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.auto.value.AutoValue;
 import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.hilt.processor.internal.ClassNames;
 import dagger.internal.codegen.extension.DaggerCollectors;
 import dagger.internal.codegen.xprocessing.XElements;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import javax.annotation.Nullable;
-import kotlin.Metadata;
-import kotlinx.metadata.Flag;
-import kotlinx.metadata.KmClass;
-import kotlinx.metadata.KmConstructor;
-import kotlinx.metadata.KmFunction;
-import kotlinx.metadata.KmProperty;
-import kotlinx.metadata.jvm.JvmExtensionsKt;
-import kotlinx.metadata.jvm.JvmFieldSignature;
-import kotlinx.metadata.jvm.JvmMetadataUtil;
-import kotlinx.metadata.jvm.JvmMethodSignature;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
 
 /** Data class of a TypeElement and its Kotlin metadata. */
 @AutoValue
@@ -79,8 +62,8 @@
   @Memoized
   boolean containsConstructorWithDefaultParam() {
     return classMetadata().constructors().stream()
-        .flatMap(constructor -> constructor.parameters().stream())
-        .anyMatch(parameter -> parameter.flags(DECLARES_DEFAULT_VALUE));
+        .flatMap(constructor -> constructor.getParameters().stream())
+        .anyMatch(parameter -> parameter.declaresDefaultValue());
   }
 
   /** Gets the synthetic method for annotations of a given field element. */
@@ -102,8 +85,7 @@
   }
 
   private Optional<MethodForAnnotations> getAnnotationMethodUncached(XFieldElement fieldElement) {
-    return findProperty(fieldElement)
-        .methodForAnnotationsSignature()
+    return Optional.ofNullable(findProperty(fieldElement).getMethodForAnnotationsSignature())
         .map(
             signature ->
                 Optional.ofNullable(methodDescriptors().get(signature))
@@ -120,20 +102,19 @@
   }
 
   private Optional<XMethodElement> getPropertyGetterUncached(XFieldElement fieldElement) {
-    return findProperty(fieldElement)
-        .getterSignature()
+    return Optional.ofNullable(findProperty(fieldElement).getGetterSignature())
         .flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature)));
   }
 
   private PropertyMetadata findProperty(XFieldElement field) {
     String fieldDescriptor = field.getJvmDescriptor();
-    if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) {
-      return classMetadata().propertiesByFieldSignature().get(fieldDescriptor);
+    if (classMetadata().getPropertiesBySignature().containsKey(fieldDescriptor)) {
+      return classMetadata().getPropertiesBySignature().get(fieldDescriptor);
     } else {
       // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124
       final String propertyName = getPropertyNameFromField(field);
-      return classMetadata().propertiesByFieldSignature().values().stream()
-          .filter(property -> propertyName.contentEquals(property.name()))
+      return classMetadata().getPropertiesBySignature().values().stream()
+          .filter(property -> propertyName.contentEquals(property.getName())) // SUPPRESS_GET_NAME_CHECK
           .collect(DaggerCollectors.onlyElement());
     }
   }
@@ -149,204 +130,7 @@
 
   /** Parse Kotlin class metadata from a given type element. */
   static KotlinMetadata from(XTypeElement typeElement) {
-    return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.create(metadataOf(typeElement)));
-  }
-
-  private static KotlinClassMetadata.Class metadataOf(XTypeElement typeElement) {
-    XAnnotation annotation = typeElement.getAnnotation(ClassNames.KOTLIN_METADATA);
-    Metadata metadataAnnotation =
-        JvmMetadataUtil.Metadata(
-            annotation.getAsInt("k"),
-            annotation.getAsIntList("mv").stream().mapToInt(Integer::intValue).toArray(),
-            annotation.getAsStringList("d1").toArray(new String[0]),
-            annotation.getAsStringList("d2").toArray(new String[0]),
-            annotation.getAsString("xs"),
-            getOptionalStringValue(annotation, "pn").orElse(null),
-            getOptionalIntValue(annotation, "xi").orElse(null));
-    KotlinClassMetadata metadata = KotlinClassMetadata.read(metadataAnnotation);
-    if (metadata == null) {
-      // Can happen if Kotlin < 1.0 or if metadata version is not supported, i.e.
-      // kotlinx-metadata-jvm is outdated.
-      throw new IllegalStateException(
-          "Unable to read Kotlin metadata due to unsupported metadata version.");
-    }
-    if (metadata instanceof KotlinClassMetadata.Class) {
-      // TODO(danysantiago): If when we need other types of metadata then move to right method.
-      return (KotlinClassMetadata.Class) metadata;
-    } else {
-      throw new IllegalStateException("Unsupported metadata type: " + metadata);
-    }
-  }
-
-  @AutoValue
-  abstract static class ClassMetadata extends BaseMetadata {
-    abstract Optional<String> companionObjectName();
-
-    abstract ImmutableSet<FunctionMetadata> constructors();
-
-    abstract ImmutableMap<String, FunctionMetadata> functionsBySignature();
-
-    abstract ImmutableMap<String, PropertyMetadata> propertiesByFieldSignature();
-
-    static ClassMetadata create(KotlinClassMetadata.Class metadata) {
-      KmClass kmClass = metadata.toKmClass();
-      ClassMetadata.Builder builder = ClassMetadata.builder(kmClass.getFlags(), kmClass.getName());
-      builder.companionObjectName(Optional.ofNullable(kmClass.getCompanionObject()));
-      kmClass.getConstructors().forEach(it -> builder.addConstructor(FunctionMetadata.create(it)));
-      kmClass.getFunctions().forEach(it -> builder.addFunction(FunctionMetadata.create(it)));
-      kmClass.getProperties().forEach(it -> builder.addProperty(PropertyMetadata.create(it)));
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_ClassMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    abstract static class Builder implements BaseMetadata.Builder<Builder> {
-      abstract Builder companionObjectName(Optional<String> companionObjectName);
-
-      abstract ImmutableSet.Builder<FunctionMetadata> constructorsBuilder();
-
-      abstract ImmutableMap.Builder<String, FunctionMetadata> functionsBySignatureBuilder();
-
-      abstract ImmutableMap.Builder<String, PropertyMetadata> propertiesByFieldSignatureBuilder();
-
-      Builder addConstructor(FunctionMetadata constructor) {
-        constructorsBuilder().add(constructor);
-        functionsBySignatureBuilder().put(constructor.signature(), constructor);
-        return this;
-      }
-
-      Builder addFunction(FunctionMetadata function) {
-        functionsBySignatureBuilder().put(function.signature(), function);
-        return this;
-      }
-
-      Builder addProperty(PropertyMetadata property) {
-        if (property.fieldSignature().isPresent()) {
-          propertiesByFieldSignatureBuilder().put(property.fieldSignature().get(), property);
-        }
-        return this;
-      }
-
-      abstract ClassMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class FunctionMetadata extends BaseMetadata {
-    abstract String signature();
-
-    abstract ImmutableList<ValueParameterMetadata> parameters();
-
-    static FunctionMetadata create(KmConstructor metadata) {
-      FunctionMetadata.Builder builder = FunctionMetadata.builder(metadata.getFlags(), "<init>");
-      metadata
-          .getValueParameters()
-          .forEach(
-              it ->
-                  builder.addParameter(ValueParameterMetadata.create(it.getFlags(), it.getName())));
-      builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString());
-      return builder.build();
-    }
-
-    static FunctionMetadata create(KmFunction metadata) {
-      FunctionMetadata.Builder builder =
-          FunctionMetadata.builder(metadata.getFlags(), metadata.getName());
-      metadata
-          .getValueParameters()
-          .forEach(
-              it ->
-                  builder.addParameter(ValueParameterMetadata.create(it.getFlags(), it.getName())));
-      builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString());
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_FunctionMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    abstract static class Builder implements BaseMetadata.Builder<Builder> {
-      abstract Builder signature(String signature);
-
-      abstract ImmutableList.Builder<ValueParameterMetadata> parametersBuilder();
-
-      Builder addParameter(ValueParameterMetadata parameter) {
-        parametersBuilder().add(parameter);
-        return this;
-      }
-
-      abstract FunctionMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class PropertyMetadata extends BaseMetadata {
-    /** Returns the JVM field descriptor of the backing field of this property. */
-    abstract Optional<String> fieldSignature();
-
-    abstract Optional<String> getterSignature();
-
-    /** Returns JVM method descriptor of the synthetic method for property annotations. */
-    abstract Optional<String> methodForAnnotationsSignature();
-
-    static PropertyMetadata create(KmProperty metadata) {
-      PropertyMetadata.Builder builder =
-          PropertyMetadata.builder(metadata.getFlags(), metadata.getName());
-      builder.fieldSignature(
-          Optional.ofNullable(JvmExtensionsKt.getFieldSignature(metadata))
-              .map(JvmFieldSignature::asString));
-      builder.getterSignature(
-          Optional.ofNullable(JvmExtensionsKt.getGetterSignature(metadata))
-              .map(JvmMethodSignature::asString));
-      builder.methodForAnnotationsSignature(
-          Optional.ofNullable(JvmExtensionsKt.getSyntheticMethodForAnnotations(metadata))
-              .map(JvmMethodSignature::asString));
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_PropertyMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    interface Builder extends BaseMetadata.Builder<Builder> {
-      Builder fieldSignature(Optional<String> signature);
-
-      Builder getterSignature(Optional<String> signature);
-
-      Builder methodForAnnotationsSignature(Optional<String> signature);
-
-      PropertyMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class ValueParameterMetadata extends BaseMetadata {
-    private static ValueParameterMetadata create(int flags, String name) {
-      return new AutoValue_KotlinMetadata_ValueParameterMetadata(flags, name);
-    }
-  }
-
-  abstract static class BaseMetadata {
-    /** Returns the Kotlin metadata flags for this property. */
-    abstract int flags();
-
-    /** returns {@code true} if the given flag (e.g. {@link Flag.IS_PRIVATE}) applies. */
-    boolean flags(Flag flag) {
-      return flag.invoke(flags());
-    }
-
-    /** Returns the simple name of this property. */
-    abstract String name();
-
-    interface Builder<BuilderT> {
-      BuilderT flags(int flags);
-
-      BuilderT name(String name);
-    }
+    return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.of(typeElement));
   }
 
   @AutoValue
@@ -360,21 +144,4 @@
     @Nullable
     abstract XMethodElement method();
   }
-
-  private static Optional<Integer> getOptionalIntValue(XAnnotation annotation, String valueName) {
-    return isValuePresent(annotation, valueName)
-        ? Optional.of(annotation.getAsInt(valueName))
-        : Optional.empty();
-  }
-
-  private static Optional<String> getOptionalStringValue(XAnnotation annotation, String valueName) {
-    return isValuePresent(annotation, valueName)
-        ? Optional.of(annotation.getAsString(valueName))
-        : Optional.empty();
-  }
-
-  private static boolean isValuePresent(XAnnotation annotation, String valueName) {
-    return annotation.getAnnotationValues().stream()
-        .anyMatch(member -> member.getName().equals(valueName));
-  }
 }
diff --git a/java/dagger/hilt/processor/internal/originatingelement/BUILD b/java/dagger/hilt/processor/internal/originatingelement/BUILD
index f4a279a..de0be5f 100644
--- a/java/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/java/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.codegen.OriginatingElement.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD
index a132b1c..8c235fb 100644
--- a/java/dagger/hilt/processor/internal/root/BUILD
+++ b/java/dagger/hilt/processor/internal/root/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Annotation processor for Hilt.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/processor/internal/root/ir/BUILD b/java/dagger/hilt/processor/internal/root/ir/BUILD
index 4bc1a29..33f5803 100644
--- a/java/dagger/hilt/processor/internal/root/ir/BUILD
+++ b/java/dagger/hilt/processor/internal/root/ir/BUILD
@@ -16,7 +16,7 @@
 #   A library containing intermediate representations of the various Hilt
 #   aggregating annotations along with logic to process them.
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
index 818abbc..cd6baed 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A processor for @dagger.hilt.android.testing.UninstallModules.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
+
 package(default_visibility = ["//:src"])
 
 java_plugin(
diff --git a/java/dagger/hilt/testing/BUILD b/java/dagger/hilt/testing/BUILD
index 59a1e94..54080e6 100644
--- a/java/dagger/hilt/testing/BUILD
+++ b/java/dagger/hilt/testing/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Testing libraries for Hilt.
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/internal/DaggerCollections.java b/java/dagger/internal/DaggerCollections.java
index cebca42..e4e70f0 100644
--- a/java/dagger/internal/DaggerCollections.java
+++ b/java/dagger/internal/DaggerCollections.java
@@ -22,6 +22,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Set;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Collection utility methods in service of Dagger internal classes. <em>Do not use</em> in client
@@ -47,14 +48,12 @@
     return new ArrayList<T>(size);
   }
 
-  /**
-   * Returns true if at least one pair of items in {@code list} are equals.
-   */
-  public static boolean hasDuplicates(List<?> list) {
+  /** Returns true if at least one pair of items in {@code list} are equals. */
+  public static <T extends @Nullable Object> boolean hasDuplicates(List<T> list) {
     if (list.size() < 2) {
       return false;
     }
-    Set<Object> asSet = new HashSet<Object>(list);
+    Set<T> asSet = new HashSet<T>(list);
     return list.size() != asSet.size();
   }
 
diff --git a/java/dagger/internal/DelegateFactory.java b/java/dagger/internal/DelegateFactory.java
index bc5cd9a..93dccf5 100644
--- a/java/dagger/internal/DelegateFactory.java
+++ b/java/dagger/internal/DelegateFactory.java
@@ -19,13 +19,16 @@
 import static dagger.internal.Preconditions.checkNotNull;
 import static dagger.internal.Providers.asDaggerProvider;
 
+import org.jspecify.annotations.Nullable;
+
 /**
  * A DelegateFactory that is used to stitch Provider/Lazy indirection based dependency cycles.
  *
  * @since 2.0.1
  */
 public final class DelegateFactory<T> implements Factory<T> {
-  private Provider<T> delegate;
+
+  private @Nullable Provider<T> delegate;
 
   @Override
   public T get() {
diff --git a/java/dagger/internal/DoubleCheck.java b/java/dagger/internal/DoubleCheck.java
index 6af8661..af82b7a 100644
--- a/java/dagger/internal/DoubleCheck.java
+++ b/java/dagger/internal/DoubleCheck.java
@@ -20,16 +20,17 @@
 import static dagger.internal.Providers.asDaggerProvider;
 
 import dagger.Lazy;
+import org.jspecify.annotations.Nullable;
 
 /**
  * A {@link Lazy} and {@link Provider} implementation that memoizes the value returned from a
  * delegate using the double-check idiom described in Item 71 of <i>Effective Java 2</i>.
  */
-public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
+public final class DoubleCheck<T extends @Nullable Object> implements Provider<T>, Lazy<T> {
   private static final Object UNINITIALIZED = new Object();
 
-  private volatile Provider<T> provider;
-  private volatile Object instance = UNINITIALIZED;
+  private volatile @Nullable Provider<T> provider;
+  private volatile @Nullable Object instance = UNINITIALIZED;
 
   private DoubleCheck(Provider<T> provider) {
     assert provider != null;
@@ -39,28 +40,33 @@
   @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
   @Override
   public T get() {
-    Object result = instance;
+    @Nullable Object result = instance;
     if (result == UNINITIALIZED) {
-      synchronized (this) {
-        result = instance;
-        if (result == UNINITIALIZED) {
-          result = provider.get();
-          instance = reentrantCheck(instance, result);
-          /* Null out the reference to the provider. We are never going to need it again, so we
-           * can make it eligible for GC. */
-          provider = null;
-        }
-      }
+      result = getSynchronized();
     }
     return (T) result;
   }
 
+  @SuppressWarnings("nullness:dereference.of.nullable") // provider is non-null
+  private synchronized @Nullable Object getSynchronized() {
+    @Nullable Object result = instance;
+    if (result == UNINITIALIZED) {
+      result = provider.get();
+      instance = reentrantCheck(instance, result);
+      /* Null out the reference to the provider. We are never going to need it again, so we
+       * can make it eligible for GC. */
+      provider = null;
+    }
+    return result;
+  }
+
   /**
    * Checks to see if creating the new instance has resulted in a recursive call. If it has, and the
    * new instance is the same as the current instance, return the instance. However, if the new
    * instance differs from the current instance, an {@link IllegalStateException} is thrown.
    */
-  private static Object reentrantCheck(Object currentInstance, Object newInstance) {
+  private static @Nullable Object reentrantCheck(
+      @Nullable Object currentInstance, @Nullable Object newInstance) {
     boolean isReentrant = currentInstance != UNINITIALIZED;
     if (isReentrant && currentInstance != newInstance) {
       throw new IllegalStateException("Scoped provider was invoked recursively returning "
@@ -71,10 +77,7 @@
   }
 
   /** Returns a {@link Provider} that caches the value from the given delegate provider. */
-  // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> delegate)"
-  // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
-  public static <P extends dagger.internal.Provider<T>, T> dagger.internal.Provider<T> provider(
-      P delegate) {
+  public static <T> dagger.internal.Provider<T> provider(dagger.internal.Provider<T> delegate) {
     checkNotNull(delegate);
     if (delegate instanceof DoubleCheck) {
       /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
@@ -95,9 +98,7 @@
   }
 
   /** Returns a {@link Lazy} that caches the value from the given provider. */
-  // This method is declared this way instead of "<T> Lazy<T> lazy(Provider<T> delegate)"
-  // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
-  public static <P extends Provider<T>, T> Lazy<T> lazy(P provider) {
+  public static <T> Lazy<T> lazy(Provider<T> provider) {
     if (provider instanceof Lazy) {
       @SuppressWarnings("unchecked")
       final Lazy<T> lazy = (Lazy<T>) provider;
diff --git a/java/dagger/internal/Factory.java b/java/dagger/internal/Factory.java
index 73bcfbc..41c4353 100644
--- a/java/dagger/internal/Factory.java
+++ b/java/dagger/internal/Factory.java
@@ -19,6 +19,7 @@
 import dagger.Provides;
 import javax.inject.Inject;
 import javax.inject.Scope;
+import org.jspecify.annotations.Nullable;
 
 /**
  * An {@linkplain Scope unscoped} {@link Provider}. While a {@link Provider} <i>may</i> apply
@@ -31,5 +32,4 @@
  * bindings. For example, {@link Provides} methods may be implemented in ways that return the same
  * instance for each call.
  */
-public interface Factory<T> extends Provider<T> {
-}
+public interface Factory<T extends @Nullable Object> extends Provider<T> {}
diff --git a/java/dagger/internal/InstanceFactory.java b/java/dagger/internal/InstanceFactory.java
index 3156fe8..96490f0 100644
--- a/java/dagger/internal/InstanceFactory.java
+++ b/java/dagger/internal/InstanceFactory.java
@@ -19,6 +19,7 @@
 import static dagger.internal.Preconditions.checkNotNull;
 
 import dagger.Lazy;
+import org.jspecify.annotations.Nullable;
 
 /**
  * A {@link Factory} implementation that returns a single instance for all invocations of {@link
@@ -29,24 +30,24 @@
  * is redundant and unnecessary. However, using this with {@link DoubleCheck#provider} is valid and
  * may be desired for testing or contractual guarantees.
  */
-public final class InstanceFactory<T> implements Factory<T>, Lazy<T> {
+public final class InstanceFactory<T extends @Nullable Object> implements Factory<T>, Lazy<T> {
   public static <T> Factory<T> create(T instance) {
     return new InstanceFactory<T>(checkNotNull(instance, "instance cannot be null"));
   }
 
-  public static <T> Factory<T> createNullable(T instance) {
+  public static <T extends @Nullable Object> Factory<T> createNullable(T instance) {
     return instance == null
         ? InstanceFactory.<T>nullInstanceFactory()
         : new InstanceFactory<T>(instance);
   }
 
   @SuppressWarnings("unchecked") // bivariant implementation
-  private static <T> InstanceFactory<T> nullInstanceFactory() {
+  private static <T extends @Nullable Object> InstanceFactory<T> nullInstanceFactory() {
     return (InstanceFactory<T>) NULL_INSTANCE_FACTORY;
   }
 
-  private static final InstanceFactory<Object> NULL_INSTANCE_FACTORY =
-      new InstanceFactory<Object>(null);
+  private static final InstanceFactory<@Nullable Object> NULL_INSTANCE_FACTORY =
+      new InstanceFactory<@Nullable Object>(null);
 
   private final T instance;
 
diff --git a/java/dagger/internal/LazyClassKeyMap.java b/java/dagger/internal/LazyClassKeyMap.java
index dabf86f..eec7909 100644
--- a/java/dagger/internal/LazyClassKeyMap.java
+++ b/java/dagger/internal/LazyClassKeyMap.java
@@ -19,6 +19,8 @@
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 /**
  * A class keyed map that delegates to a string keyed map under the hood.
@@ -37,11 +39,11 @@
   }
 
   @Override
-  public V get(Object key) {
+  public V get(@Nullable Object key) {
     if (!(key instanceof Class)) {
       throw new IllegalArgumentException("Key must be a class");
     }
-    return delegate.get(((Class<?>) key).getName());
+    return (@NonNull V) delegate.get(((Class<?>) key).getName());
   }
 
   @Override
@@ -64,7 +66,7 @@
   }
 
   @Override
-  public boolean containsKey(Object key) {
+  public boolean containsKey(@Nullable Object key) {
     if (!(key instanceof Class)) {
       throw new IllegalArgumentException("Key must be a class");
     }
@@ -72,7 +74,7 @@
   }
 
   @Override
-  public boolean containsValue(Object value) {
+  public boolean containsValue(@Nullable Object value) {
     return delegate.containsValue(value);
   }
 
@@ -92,7 +94,7 @@
 
   // The dagger map binding should be a immutable map.
   @Override
-  public V remove(Object key) {
+  public V remove(@Nullable Object key) {
     throw new UnsupportedOperationException("Dagger map bindings are immutable");
   }
 
@@ -111,15 +113,15 @@
     throw new UnsupportedOperationException("Dagger map bindings are immutable");
   }
 
-  /** A factory for {@code LazyClassKeyMap}. */
-  public static class Factory<V> implements Provider<Map<Class<?>, V>> {
-    MapFactory<String, V> delegate;
+  /** Wrapper around {@link MapFactory}. */
+  public static class MapFactory<V> implements Factory<Map<Class<?>, V>> {
+    Factory<Map<String, V>> delegate;
 
-    public static <V> Factory<V> of(MapFactory<String, V> delegate) {
-      return new Factory<>(delegate);
+    public static <V> MapFactory<V> of(Factory<Map<String, V>> delegate) {
+      return new MapFactory<V>(delegate);
     }
 
-    private Factory(MapFactory<String, V> delegate) {
+    private MapFactory(Factory<Map<String, V>> delegate) {
       this.delegate = delegate;
     }
 
@@ -128,4 +130,22 @@
       return LazyClassKeyMap.of(delegate.get());
     }
   }
+
+  /** Wrapper around for {@link MapProviderFactory}. */
+  public static class MapProviderFactory<V> implements Factory<Map<Class<?>, Provider<V>>> {
+    Factory<Map<String, Provider<V>>> delegate;
+
+    public static <V> MapProviderFactory<V> of(Factory<Map<String, Provider<V>>> delegate) {
+      return new MapProviderFactory<V>(delegate);
+    }
+
+    private MapProviderFactory(Factory<Map<String, Provider<V>>> delegate) {
+      this.delegate = delegate;
+    }
+
+    @Override
+    public Map<Class<?>, Provider<V>> get() {
+      return LazyClassKeyMap.of(delegate.get());
+    }
+  }
 }
diff --git a/java/dagger/internal/Preconditions.java b/java/dagger/internal/Preconditions.java
index d21e594..2a1ef05 100644
--- a/java/dagger/internal/Preconditions.java
+++ b/java/dagger/internal/Preconditions.java
@@ -16,6 +16,7 @@
 
 package dagger.internal;
 
+import org.jspecify.annotations.Nullable;
 
 /**
  * An adaptation of Guava's {@code com.google.common.base.Preconditions} that is specially tailored
@@ -29,7 +30,7 @@
    * @return the non-null reference that was validated
    * @throws NullPointerException if {@code reference} is null
    */
-  public static <T> T checkNotNull(T reference) {
+  public static <T> T checkNotNull(@Nullable T reference) {
     if (reference == null) {
       throw new NullPointerException();
     }
@@ -106,9 +107,10 @@
             "errorMessageTemplate has more than one format specifier");
       }
       String argString =
-          errorMessageArg instanceof Class
-              ? ((Class) errorMessageArg).getCanonicalName()
-              : String.valueOf(errorMessageArg);
+          String.valueOf(
+              errorMessageArg instanceof Class
+                  ? ((Class) errorMessageArg).getCanonicalName()
+                  : errorMessageArg);
       throw new NullPointerException(errorMessageTemplate.replace("%s", argString));
     }
     return reference;
diff --git a/java/dagger/internal/Provider.java b/java/dagger/internal/Provider.java
index e388601..5732045 100644
--- a/java/dagger/internal/Provider.java
+++ b/java/dagger/internal/Provider.java
@@ -16,10 +16,11 @@
 
 package dagger.internal;
 
+import org.jspecify.annotations.Nullable;
+
 /**
- * Internal Provider interface to make support for {@code javax.inject.Provider} and
- * {@code jakarta.inject.Provider} easier. Do not use outside of Dagger implementation code.
+ * Internal Provider interface to make support for {@code javax.inject.Provider} and {@code
+ * jakarta.inject.Provider} easier. Do not use outside of Dagger implementation code.
  */
-// TODO(erichang): Make this also extend the Jakarta Provider
-public interface Provider<T> extends javax.inject.Provider<T> {
-}
+public interface Provider<T extends @Nullable Object>
+    extends javax.inject.Provider<T>, jakarta.inject.Provider<T> {}
diff --git a/java/dagger/internal/Providers.java b/java/dagger/internal/Providers.java
index 60ec83f..bf164eb 100644
--- a/java/dagger/internal/Providers.java
+++ b/java/dagger/internal/Providers.java
@@ -18,12 +18,19 @@
 
 import static dagger.internal.Preconditions.checkNotNull;
 
+import org.jspecify.annotations.Nullable;
+
 /** Helper class for utility functions dealing with Providers. */
 public final class Providers {
 
   /** Converts a javax provider to a Dagger internal provider. */
-  public static <T> Provider<T> asDaggerProvider(final javax.inject.Provider<T> provider) {
+  @SuppressWarnings("unchecked")
+  public static <T extends @Nullable Object> Provider<T> asDaggerProvider(
+      final javax.inject.Provider<T> provider) {
     checkNotNull(provider);
+    if (provider instanceof Provider) {
+      return (Provider) provider;
+    }
     return new Provider<T>() {
         @Override public T get() {
           return provider.get();
diff --git a/java/dagger/internal/SingleCheck.java b/java/dagger/internal/SingleCheck.java
index 32ba83a..0b0273f 100644
--- a/java/dagger/internal/SingleCheck.java
+++ b/java/dagger/internal/SingleCheck.java
@@ -19,15 +19,17 @@
 import static dagger.internal.Preconditions.checkNotNull;
 import static dagger.internal.Providers.asDaggerProvider;
 
+import org.jspecify.annotations.Nullable;
+
 /**
  * A {@link Provider} implementation that memoizes the result of another {@link Provider} using
  * simple lazy initialization, not the double-checked lock pattern.
  */
-public final class SingleCheck<T> implements Provider<T> {
+public final class SingleCheck<T extends @Nullable Object> implements Provider<T> {
   private static final Object UNINITIALIZED = new Object();
 
-  private volatile Provider<T> provider;
-  private volatile Object instance = UNINITIALIZED;
+  private volatile @Nullable Provider<T> provider;
+  private volatile @Nullable Object instance = UNINITIALIZED;
 
   private SingleCheck(Provider<T> provider) {
     assert provider != null;
@@ -37,10 +39,10 @@
   @SuppressWarnings("unchecked") // cast only happens when result comes from the delegate provider
   @Override
   public T get() {
-    Object local = instance;
+    @Nullable Object local = instance;
     if (local == UNINITIALIZED) {
       // provider is volatile and might become null after the check, so retrieve the provider first
-      Provider<T> providerReference = provider;
+      @Nullable Provider<T> providerReference = provider;
       if (providerReference == null) {
         // The provider was null, so the instance must already be set
         local = instance;
@@ -57,9 +59,7 @@
   }
 
   /** Returns a {@link Provider} that caches the value from the given delegate provider. */
-  // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> provider)"
-  // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
-  public static <P extends Provider<T>, T> Provider<T> provider(P provider) {
+  public static <T> Provider<T> provider(Provider<T> provider) {
     // If a scoped @Binds delegates to a scoped binding, don't cache the value again.
     if (provider instanceof SingleCheck || provider instanceof DoubleCheck) {
       return provider;
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index 80ca8d7..2de6ffc 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -20,7 +20,7 @@
     "//:build_defs.bzl",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/internal/codegen/ComponentProcessor.java b/java/dagger/internal/codegen/ComponentProcessor.java
index 2a68a4b..e97493c 100644
--- a/java/dagger/internal/codegen/ComponentProcessor.java
+++ b/java/dagger/internal/codegen/ComponentProcessor.java
@@ -120,6 +120,11 @@
   }
 
   @Override
+  public void preRound(XProcessingEnv env, XRoundEnv roundEnv) {
+    delegate.onProcessingRoundBegin();
+  }
+
+  @Override
   public void postRound(XProcessingEnv env, XRoundEnv roundEnv) {
     delegate.postRound(env, roundEnv);
   }
diff --git a/java/dagger/internal/codegen/DelegateComponentProcessor.java b/java/dagger/internal/codegen/DelegateComponentProcessor.java
index 432daa6..754b4d9 100644
--- a/java/dagger/internal/codegen/DelegateComponentProcessor.java
+++ b/java/dagger/internal/codegen/DelegateComponentProcessor.java
@@ -33,14 +33,13 @@
 import dagger.internal.codegen.base.SourceFileGenerationException;
 import dagger.internal.codegen.base.SourceFileGenerator;
 import dagger.internal.codegen.base.SourceFileHjarGenerator;
-import dagger.internal.codegen.binding.BindingGraphFactory;
 import dagger.internal.codegen.binding.ComponentDescriptor;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.InjectBindingRegistry;
 import dagger.internal.codegen.binding.MembersInjectionBinding;
 import dagger.internal.codegen.binding.ModuleDescriptor;
 import dagger.internal.codegen.binding.MonitoringModules;
 import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule;
@@ -74,7 +73,7 @@
       new XProcessingEnvConfig.Builder().disableAnnotatedElementValidation(true).build();
 
   @Inject InjectBindingRegistry injectBindingRegistry;
-  @Inject SourceFileGenerator<ProvisionBinding> factoryGenerator;
+  @Inject SourceFileGenerator<ContributionBinding> factoryGenerator;
   @Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
   @Inject ImmutableList<XProcessingStep> processingSteps;
   @Inject ValidationBindingGraphPlugins validationBindingGraphPlugins;
@@ -108,15 +107,19 @@
     DaggerDelegateComponentProcessor_Injector.factory()
         .create(env, plugins, legacyPlugins)
         .inject(this);
+    validationBindingGraphPlugins.initializePlugins();
+    externalBindingGraphPlugins.initializePlugins();
   }
 
   public Iterable<XProcessingStep> processingSteps() {
-    validationBindingGraphPlugins.initializePlugins();
-    externalBindingGraphPlugins.initializePlugins();
 
     return processingSteps;
   }
 
+  public void onProcessingRoundBegin() {
+    externalBindingGraphPlugins.onProcessingRoundBegin();
+  }
+
   public void postRound(XProcessingEnv env, XRoundEnv roundEnv) {
     if (!roundEnv.isProcessingOver()) {
       try {
@@ -182,10 +185,6 @@
 
     @Binds
     @IntoSet
-    ClearableCache bindingGraphFactory(BindingGraphFactory cache);
-
-    @Binds
-    @IntoSet
     ClearableCache componentValidator(ComponentValidator cache);
 
     @Binds
@@ -200,7 +199,7 @@
   @Module
   interface SourceFileGeneratorsModule {
     @Provides
-    static SourceFileGenerator<ProvisionBinding> factoryGenerator(
+    static SourceFileGenerator<ContributionBinding> factoryGenerator(
         FactoryGenerator generator,
         CompilerOptions compilerOptions,
         XProcessingEnv processingEnv) {
diff --git a/java/dagger/internal/codegen/KspComponentProcessor.java b/java/dagger/internal/codegen/KspComponentProcessor.java
index 8b07f93..5fc6363 100644
--- a/java/dagger/internal/codegen/KspComponentProcessor.java
+++ b/java/dagger/internal/codegen/KspComponentProcessor.java
@@ -59,6 +59,11 @@
   }
 
   @Override
+  public void preRound(XProcessingEnv env, XRoundEnv roundEnv) {
+    delegate.onProcessingRoundBegin();
+  }
+
+  @Override
   public void postRound(XProcessingEnv env, XRoundEnv roundEnv) {
     delegate.postRound(env, roundEnv);
   }
diff --git a/java/dagger/internal/codegen/ServiceLoaders.java b/java/dagger/internal/codegen/ServiceLoaders.java
index 95773fa..974f36e 100644
--- a/java/dagger/internal/codegen/ServiceLoaders.java
+++ b/java/dagger/internal/codegen/ServiceLoaders.java
@@ -30,8 +30,6 @@
 
   /**
    * Returns the loaded services for the given class.
-   *
-   * <p>Note: This should only be called in Javac. This method will throw if called in KSP.
    */
   static <T> ImmutableSet<T> loadServices(XProcessingEnv processingEnv, Class<T> clazz) {
     return ImmutableSet.copyOf(ServiceLoader.load(clazz, classLoaderFor(processingEnv, clazz)));
diff --git a/java/dagger/internal/codegen/base/FrameworkTypes.java b/java/dagger/internal/codegen/base/FrameworkTypes.java
index e39aeab..04eaf2e 100644
--- a/java/dagger/internal/codegen/base/FrameworkTypes.java
+++ b/java/dagger/internal/codegen/base/FrameworkTypes.java
@@ -31,7 +31,11 @@
 public final class FrameworkTypes {
   // TODO(erichang): Add the Jakarta Provider here
   private static final ImmutableSet<ClassName> PROVISION_TYPES =
-      ImmutableSet.of(TypeNames.PROVIDER, TypeNames.LAZY, TypeNames.MEMBERS_INJECTOR);
+      ImmutableSet.of(
+          TypeNames.PROVIDER,
+          TypeNames.JAKARTA_PROVIDER,
+          TypeNames.LAZY,
+          TypeNames.MEMBERS_INJECTOR);
 
   // NOTE(beder): ListenableFuture is not considered a producer framework type because it is not
   // defined by the framework, so we can't treat it specially in ordinary Dagger.
@@ -41,6 +45,22 @@
   private static final ImmutableSet<ClassName> ALL_FRAMEWORK_TYPES =
       ImmutableSet.<ClassName>builder().addAll(PROVISION_TYPES).addAll(PRODUCTION_TYPES).build();
 
+  public static final ImmutableSet<ClassName> SET_VALUE_FRAMEWORK_TYPES =
+      ImmutableSet.of(TypeNames.PRODUCED);
+
+  public static final ImmutableSet<ClassName> MAP_VALUE_FRAMEWORK_TYPES =
+      ImmutableSet.of(
+          TypeNames.PRODUCED,
+          TypeNames.PRODUCER,
+          TypeNames.PROVIDER,
+          TypeNames.JAKARTA_PROVIDER);
+
+  // This is a set of types that are disallowed from use, but also aren't framework types in the
+  // sense that they aren't supported. Like we shouldn't try to unwrap these if we see them, though
+  // we shouldn't see them at all if they are correctly caught in validation.
+  private static final ImmutableSet<ClassName> DISALLOWED_TYPES =
+      ImmutableSet.of(TypeNames.DAGGER_PROVIDER);
+
   /** Returns true if the type represents a producer-related framework type. */
   public static boolean isProducerType(XType type) {
     return typeIsOneOf(PRODUCTION_TYPES, type);
@@ -51,6 +71,18 @@
     return typeIsOneOf(ALL_FRAMEWORK_TYPES, type);
   }
 
+  public static boolean isSetValueFrameworkType(XType type) {
+    return typeIsOneOf(SET_VALUE_FRAMEWORK_TYPES, type);
+  }
+
+  public static boolean isMapValueFrameworkType(XType type) {
+    return typeIsOneOf(MAP_VALUE_FRAMEWORK_TYPES, type);
+  }
+
+  public static boolean isDisallowedType(XType type) {
+    return typeIsOneOf(DISALLOWED_TYPES, type);
+  }
+
   private static boolean typeIsOneOf(Set<ClassName> classNames, XType type) {
     return classNames.stream().anyMatch(className -> isTypeOf(type, className));
   }
diff --git a/java/dagger/internal/codegen/base/MapType.java b/java/dagger/internal/codegen/base/MapType.java
index c4ba838..ba4b1e7 100644
--- a/java/dagger/internal/codegen/base/MapType.java
+++ b/java/dagger/internal/codegen/base/MapType.java
@@ -23,15 +23,24 @@
 
 import androidx.room.compiler.processing.XType;
 import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.TypeName;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.xprocessing.XTypes;
 
 /** Information about a {@link java.util.Map} type. */
 @AutoValue
 public abstract class MapType {
+  // TODO(b/28555349): support PROVIDER_OF_LAZY here too
+  // TODO(b/376124787): We could consolidate this with a similar list in FrameworkTypes
+  // if we had a better way to go from RequestKind to framework ClassName or vice versa
+  /** The valid framework request kinds allowed on a multibinding map value. */
+  private static final ImmutableSet<RequestKind> VALID_FRAMEWORK_REQUEST_KINDS =
+      ImmutableSet.of(RequestKind.PROVIDER, RequestKind.PRODUCER, RequestKind.PRODUCED);
+
   private XType type;
 
   /** The map type itself. */
@@ -74,35 +83,45 @@
 
   /** Returns {@code true} if the raw type of {@link #valueType()} is a framework type. */
   public boolean valuesAreFrameworkType() {
-    return FrameworkTypes.isFrameworkType(valueType());
+    return valueRequestKind() != RequestKind.INSTANCE;
   }
 
   /**
-   * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code
-   * Producer<V>}.
+   * Returns the map's {@link #valueType()} without any wrapping framework type, if one exists.
    *
-   * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
-   *     framework type
+   * <p>In particular, this method returns {@code V} for all of the following map types:
+   * {@code Map<K,V>}, {@code Map<K,Provider<V>>}, {@code Map<K,Producer<V>>}, and
+   * {@code Map<K,Produced<V>>}.
+   *
+   * <p>Note that we don't consider {@code Lazy} a framework type for this particular case, so this
+   * method will return {@code Lazy<V>} for {@code Map<K,Lazy<V>>}.
+   *
+   * @throws IllegalStateException if {@link #isRawType()} is true.
    */
   public XType unwrappedFrameworkValueType() {
-    checkState(valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", type());
-    return uncheckedUnwrappedValueType();
+    return valuesAreFrameworkType() ? unwrapType(valueType()) : valueType();
   }
 
   /**
-   * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}.
+   * Returns the {@link RequestKind} of the {@link #valueType()}.
    *
-   * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
-   *     {@code WrappingClass<V>}
+   * @throws IllegalArgumentException if {@link #isRawType()} is true.
    */
-  // TODO(b/202033221): Consider using stricter input type, e.g. FrameworkType.
-  public XType unwrappedValueType(ClassName wrappingClass) {
-    checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this);
-    return uncheckedUnwrappedValueType();
-  }
-
-  private XType uncheckedUnwrappedValueType() {
-    return unwrapType(valueType());
+  public RequestKind valueRequestKind() {
+    checkArgument(!isRawType());
+    RequestKind requestKind = RequestKinds.getRequestKind(valueType());
+    if (VALID_FRAMEWORK_REQUEST_KINDS.contains(requestKind)) {
+      return requestKind;
+    } else if (requestKind == RequestKind.PROVIDER_OF_LAZY) {
+      // This is kind of a weird case. We don't support Map<K, Lazy<V>>, so we also don't support
+      // Map<K, Provider<Lazy<V>>> directly. However, if the user bound that themselves, we don't
+      // want that to get confused as a normal instance request, so return PROVIDER here.
+      return RequestKind.PROVIDER;
+    } else {
+      // Not all RequestKinds are supported, so if there's a map value that matches an unsupported
+      // RequestKind, just treat it like it is a normal instance request.
+      return RequestKind.INSTANCE;
+    }
   }
 
   /** {@code true} if {@code type} is a {@link java.util.Map} type. */
diff --git a/java/dagger/internal/codegen/base/RequestKinds.java b/java/dagger/internal/codegen/base/RequestKinds.java
index a9c7e83..fdf1c20 100644
--- a/java/dagger/internal/codegen/base/RequestKinds.java
+++ b/java/dagger/internal/codegen/base/RequestKinds.java
@@ -39,6 +39,11 @@
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.TypeName;
 import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Node;
 import dagger.internal.codegen.model.RequestKind;
 
 /** Utility methods for {@link RequestKind}s. */
@@ -92,6 +97,8 @@
 
   private static final ImmutableMap<RequestKind, ClassName> FRAMEWORK_CLASSES =
       ImmutableMap.of(
+          // Default to the javax Provider since that is what is used for the binding graph
+          // representation.
           PROVIDER, TypeNames.PROVIDER,
           LAZY, TypeNames.LAZY,
           PRODUCER, TypeNames.PRODUCER,
@@ -106,10 +113,15 @@
       return RequestKind.INSTANCE;
     }
 
-    if (isTypeOf(type, TypeNames.PROVIDER) && isTypeOf(unwrapType(type), TypeNames.LAZY)) {
+    if ((isTypeOf(type, TypeNames.PROVIDER) || isTypeOf(type, TypeNames.JAKARTA_PROVIDER))
+        && isTypeOf(unwrapType(type), TypeNames.LAZY)) {
       return RequestKind.PROVIDER_OF_LAZY;
     }
 
+    if (isTypeOf(type, TypeNames.JAKARTA_PROVIDER)) {
+      return RequestKind.PROVIDER;
+    }
+
     return FRAMEWORK_CLASSES.keySet().stream()
         .filter(kind -> isTypeOf(type, FRAMEWORK_CLASSES.get(kind)))
         .collect(toOptional())
@@ -162,21 +174,38 @@
    * Returns {@code true} if requests for {@code requestKind} can be satisfied by a production
    * binding.
    */
-  public static boolean canBeSatisfiedByProductionBinding(RequestKind requestKind) {
+  public static boolean canBeSatisfiedByProductionBinding(
+      RequestKind requestKind, boolean isEntryPoint) {
     switch (requestKind) {
-      case INSTANCE:
       case PROVIDER:
       case LAZY:
       case PROVIDER_OF_LAZY:
       case MEMBERS_INJECTION:
         return false;
+      case PRODUCED: // TODO(b/337087142) Requires implementation for entry point.
+      case INSTANCE:
+        return !isEntryPoint;
       case PRODUCER:
-      case PRODUCED:
       case FUTURE:
         return true;
     }
     throw new AssertionError();
   }
 
+  public static boolean dependencyCanBeProduction(DependencyEdge edge, BindingGraph graph) {
+    Node source = graph.network().incidentNodes(edge).source();
+    boolean isEntryPoint = source instanceof ComponentNode;
+    boolean isValidRequest =
+        canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind(), isEntryPoint);
+    if (isEntryPoint) {
+      return isValidRequest;
+    }
+    if (source instanceof Binding) {
+      return isValidRequest && ((Binding) source).isProduction();
+    }
+    throw new IllegalArgumentException(
+        "expected a dagger.internal.codegen.model.Binding or ComponentNode: " + source);
+  }
+
   private RequestKinds() {}
 }
diff --git a/java/dagger/internal/codegen/base/SourceFileGenerator.java b/java/dagger/internal/codegen/base/SourceFileGenerator.java
index dfe14b1..e4fd5b6 100644
--- a/java/dagger/internal/codegen/base/SourceFileGenerator.java
+++ b/java/dagger/internal/codegen/base/SourceFileGenerator.java
@@ -19,16 +19,17 @@
 import static androidx.room.compiler.processing.JavaPoetExtKt.addOriginatingElement;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.CAST;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.DEPRECATION;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.KOTLIN_INTERNAL;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNINITIALIZED;
 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
 
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XFiler;
 import androidx.room.compiler.processing.XMessager;
 import androidx.room.compiler.processing.XProcessingEnv;
-import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.AnnotationSpec;
@@ -61,29 +62,15 @@
     this(delegate.filer, delegate.processingEnv);
   }
 
-  /**
-   * Generates a source file to be compiled for {@code T}. Writes any generation exception to {@code
-   * messager} and does not throw.
-   */
+  /** Generates a source file to be compiled for {@code T}. */
   public void generate(T input, XMessager messager) {
-    try {
-      generate(input);
-    } catch (SourceFileGenerationException e) {
-      e.printMessageTo(messager);
-    }
+    generate(input);
   }
 
   /** Generates a source file to be compiled for {@code T}. */
-  public void generate(T input) throws SourceFileGenerationException {
+  public void generate(T input) {
     for (TypeSpec.Builder type : topLevelTypes(input)) {
-      try {
-        filer.write(buildJavaFile(input, type), XFiler.Mode.Isolating);
-      } catch (RuntimeException e) {
-        // if the code above threw a SFGE, use that
-        Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
-        // otherwise, throw a new one
-        throw new SourceFileGenerationException(Optional.empty(), e, originatingElement(input));
-      }
+      filer.write(buildJavaFile(input, type), XFiler.Mode.Isolating);
     }
   }
 
@@ -106,7 +93,7 @@
         AnnotationSpecs.suppressWarnings(
             ImmutableSet.<Suppression>builder()
                 .addAll(warningSuppressions())
-                .add(UNCHECKED, RAWTYPES, KOTLIN_INTERNAL, CAST)
+                .add(UNCHECKED, RAWTYPES, KOTLIN_INTERNAL, CAST, DEPRECATION, UNINITIALIZED)
                 .build()));
 
     String packageName = closestEnclosingTypeElement(originatingElement).getPackageName();
diff --git a/java/dagger/internal/codegen/base/SourceFileHjarGenerator.java b/java/dagger/internal/codegen/base/SourceFileHjarGenerator.java
index 6857c36..8e93a61 100644
--- a/java/dagger/internal/codegen/base/SourceFileHjarGenerator.java
+++ b/java/dagger/internal/codegen/base/SourceFileHjarGenerator.java
@@ -201,11 +201,16 @@
   }
 
   private FieldSpec skeletonField(FieldSpec completeField) {
-    return FieldSpec.builder(
-            completeField.type,
-            completeField.name,
-            completeField.modifiers.toArray(new Modifier[0]))
-        .addAnnotations(completeField.annotations)
-        .build();
+    FieldSpec.Builder skeleton =
+        FieldSpec.builder(
+                completeField.type,
+                completeField.name,
+                completeField.modifiers.toArray(new Modifier[0]))
+            .addAnnotations(completeField.annotations);
+    if (completeField.modifiers.contains(Modifier.FINAL)) {
+      // Final fields must be initialized so use the default value.
+      skeleton.initializer(getDefaultValueCodeBlock(completeField.type));
+    }
+    return skeleton.build();
   }
 }
diff --git a/java/dagger/internal/codegen/binding/AnnotationExpression.java b/java/dagger/internal/codegen/binding/AnnotationExpression.java
index 535a7ef..db0bf55 100644
--- a/java/dagger/internal/codegen/binding/AnnotationExpression.java
+++ b/java/dagger/internal/codegen/binding/AnnotationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.binding;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static androidx.room.compiler.processing.XTypeKt.isArray;
 import static dagger.internal.codegen.binding.SourceFiles.classFileName;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
@@ -26,11 +27,11 @@
 import static dagger.internal.codegen.xprocessing.XTypes.asArray;
 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
 
+import androidx.room.compiler.codegen.XClassName;
 import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XAnnotationValue;
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
-import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import dagger.internal.codegen.javapoet.TypeNames;
 
@@ -47,7 +48,7 @@
  */
 public final class AnnotationExpression {
   private final XAnnotation annotation;
-  private final ClassName creatorClass;
+  private final XClassName creatorClass;
 
   AnnotationExpression(XAnnotation annotation) {
     this.annotation = annotation;
@@ -65,7 +66,7 @@
   private CodeBlock getAnnotationInstanceExpression(XAnnotation annotation) {
     return CodeBlock.of(
         "$T.$L($L)",
-        creatorClass,
+        toJavaPoet(creatorClass),
         createMethodName(annotation.getType().getTypeElement()),
         makeParametersCodeBlock(
             annotation.getAnnotationValues().stream()
@@ -77,11 +78,11 @@
    * Returns the name of the generated class that contains the static {@code create} methods for an
    * annotation type.
    */
-  public static ClassName getAnnotationCreatorClassName(XTypeElement annotationType) {
-    ClassName annotationTypeName = annotationType.getClassName();
-    return annotationTypeName
-        .topLevelClassName()
-        .peerClass(classFileName(annotationTypeName) + "Creator");
+  public static XClassName getAnnotationCreatorClassName(XTypeElement annotationType) {
+    XClassName annotationTypeName = annotationType.asClassName();
+    return XClassName.Companion.get(
+        annotationTypeName.getPackageName(),
+        classFileName(annotationTypeName) + "Creator");
   }
 
   public static String createMethodName(XTypeElement annotationType) {
diff --git a/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java b/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java
new file mode 100644
index 0000000..21220e6
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#ASSISTED_FACTORY}. */
+@CheckReturnValue
+@AutoValue
+public abstract class AssistedFactoryBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.ASSISTED_FACTORY;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of(
+        DependencyRequest.builder()
+            .key(assistedInjectKey())
+            .kind(RequestKind.PROVIDER)
+            .build());
+  }
+
+  /** Returns the key for the associated {@code @AssistedInject} binding. */
+  public abstract Key assistedInjectKey();
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_AssistedFactoryBinding.Builder();
+  }
+
+  /** A {@link AssistedFactoryBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<AssistedFactoryBinding, Builder> {
+    abstract Builder assistedInjectKey(Key assistedInjectKey);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java b/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java
new file mode 100644
index 0000000..b5fef76
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#ASSISTED_INJECTION}. */
+@CheckReturnValue
+@AutoValue
+public abstract class AssistedInjectionBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.ASSISTED_INJECTION;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  /** Dependencies necessary to invoke the {@code @Inject} annotated constructor. */
+  public abstract ImmutableSet<DependencyRequest> constructorDependencies();
+
+  /** {@link InjectionSite}s for all {@code @Inject} members. */
+  public abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.<DependencyRequest>builder()
+        .addAll(constructorDependencies())
+        .addAll(
+            injectionSites().stream()
+                .flatMap(i -> i.dependencies().stream())
+                .collect(toImmutableSet()))
+        .build();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_AssistedInjectionBinding.Builder();
+  }
+
+  /** A {@link AssistedInjectionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<AssistedInjectionBinding, Builder> {
+    abstract Builder constructorDependencies(Iterable<DependencyRequest> constructorDependencies);
+
+    abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/Binding.java b/java/dagger/internal/codegen/binding/Binding.java
index 250e608..d706485 100644
--- a/java/dagger/internal/codegen/binding/Binding.java
+++ b/java/dagger/internal/codegen/binding/Binding.java
@@ -16,16 +16,7 @@
 
 package dagger.internal.codegen.binding;
 
-import static com.google.common.base.Suppliers.memoize;
-import static dagger.internal.codegen.xprocessing.XElements.isAbstract;
-import static dagger.internal.codegen.xprocessing.XElements.isStatic;
-
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.model.Scope;
 import java.util.Optional;
 
 /**
@@ -35,77 +26,19 @@
  * subtypes.
  */
 public abstract class Binding extends BindingDeclaration {
-
-  /**
-   * Returns {@code true} if using this binding requires an instance of the {@link
-   * #contributingModule()}.
-   */
-  public boolean requiresModuleInstance() {
-    return contributingModule().isPresent()
-        && bindingElement().isPresent()
-        && !isAbstract(bindingElement().get())
-        && !isStatic(bindingElement().get());
-  }
-
-  /**
-   * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
-   * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
-   * non-nullable dependency requests}.
-   */
-  public abstract boolean isNullable();
-
-  /** The kind of binding this instance represents. */
-  public abstract BindingKind kind();
+  /** Returns the optional {@link BindingType}.  */
+  abstract Optional<BindingType> optionalBindingType();
 
   /** The {@link BindingType} of this binding. */
-  public abstract BindingType bindingType();
+  public final BindingType bindingType() {
+    if (optionalBindingType().isPresent()) {
+      return optionalBindingType().get();
+    }
+    throw new AssertionError("bindingType() is not set: " + this);
+  }
 
   /** The {@link FrameworkType} of this binding. */
   public final FrameworkType frameworkType() {
     return FrameworkType.forBindingType(bindingType());
   }
-
-  /**
-   * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding as
-   * defined by the user-defined injection sites.
-   */
-  public abstract ImmutableSet<DependencyRequest> explicitDependencies();
-
-  /**
-   * The set of {@link DependencyRequest dependencies} that are added by the framework rather than a
-   * user-defined injection site. This returns an unmodifiable set.
-   */
-  public ImmutableSet<DependencyRequest> implicitDependencies() {
-    return ImmutableSet.of();
-  }
-
-  private final Supplier<ImmutableSet<DependencyRequest>> dependencies =
-      memoize(
-          () -> {
-            ImmutableSet<DependencyRequest> implicitDependencies = implicitDependencies();
-            return ImmutableSet.copyOf(
-                implicitDependencies.isEmpty()
-                    ? explicitDependencies()
-                    : Sets.union(implicitDependencies, explicitDependencies()));
-          });
-
-  /**
-   * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is the
-   * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an
-   * unmodifiable set.
-   */
-  public final ImmutableSet<DependencyRequest> dependencies() {
-    return dependencies.get();
-  }
-
-  /**
-   * If this binding's key's type parameters are different from those of the {@link
-   * #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s unresolved
-   * type.
-   */
-  public abstract Optional<? extends Binding> unresolved();
-
-  public Optional<Scope> scope() {
-    return Optional.empty();
-  }
 }
diff --git a/java/dagger/internal/codegen/binding/BindingDeclaration.java b/java/dagger/internal/codegen/binding/BindingDeclaration.java
index dd24c98..54c8c49 100644
--- a/java/dagger/internal/codegen/binding/BindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/BindingDeclaration.java
@@ -16,74 +16,41 @@
 
 package dagger.internal.codegen.binding;
 
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-import static dagger.internal.codegen.extension.Optionals.emptiesLast;
-import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static java.util.Comparator.comparing;
-
-import androidx.room.compiler.processing.XElement;
-import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
 import dagger.internal.codegen.model.BindingKind;
-import dagger.internal.codegen.model.Key;
-import dagger.internal.codegen.xprocessing.XElements;
-import java.util.Comparator;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Scope;
 import java.util.Optional;
 
 /** An object that declares or specifies a binding. */
-public abstract class BindingDeclaration {
-  /**
-   * A comparator that compares binding declarations with elements.
-   *
-   * <p>Compares, in order:
-   *
-   * <ol>
-   *   <li>Contributing module or enclosing type name
-   *   <li>Binding element's simple name
-   *   <li>Binding element's type
-   * </ol>
-   *
-   * Any binding declarations without elements are last.
-   */
-  public static final Comparator<BindingDeclaration> COMPARATOR =
-      comparing(
-              (BindingDeclaration declaration) ->
-                  declaration.contributingModule().isPresent()
-                      ? declaration.contributingModule()
-                      : declaration.bindingTypeElement(),
-              emptiesLast(comparing(XTypeElement::getQualifiedName)))
-          .thenComparing(
-              (BindingDeclaration declaration) -> declaration.bindingElement(),
-              emptiesLast(
-                  comparing((XElement element) -> getSimpleName(element))
-                      .thenComparing((XElement element) -> toJavac(element).asType().toString())));
-
-  /** The {@link Key} of this declaration. */
-  public abstract Key key();
+public abstract class BindingDeclaration extends Declaration {
 
   /**
-   * The {@link XElement} that declares this binding. Absent for {@linkplain BindingKind binding
-   * kinds} that are not always declared by exactly one element.
-   *
-   * <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
-   * {@code @IntoSet} bindings for the same key will have a synthetic binding that depends on all
-   * contributions, but with no identifiying binding element. A {@code @Multibinds} method will also
-   * contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
-   * the same component (and contribute to one single binding), it has no binding element.
+   * Returns {@code true} if using this binding requires an instance of the {@link
+   * #contributingModule()}.
    */
-  public abstract Optional<XElement> bindingElement();
+  public abstract boolean requiresModuleInstance();
 
   /**
-   * The type enclosing the {@link #bindingElement()}, or {@link Optional#empty()} if {@link
-   * #bindingElement()} is empty.
+   * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
+   * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
+   * non-nullable dependency requests}.
    */
-  public final Optional<XTypeElement> bindingTypeElement() {
-    return bindingElement().map(XElements::closestEnclosingTypeElement);
-  }
+  public abstract boolean isNullable();
+
+  /** The kind of binding this instance represents. */
+  public abstract BindingKind kind();
+
+  /** The set of {@link DependencyRequest dependencies} required to satisfy this binding. */
+  public abstract ImmutableSet<DependencyRequest> dependencies();
 
   /**
-   * The installed module class that contributed the {@link #bindingElement()}. May be a subclass of
-   * the class that contains {@link #bindingElement()}. Absent if {@link #bindingElement()} is
-   * empty.
+   * If this binding's key's type parameters are different from those of the {@link
+   * #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s unresolved
+   * type.
    */
-  public abstract Optional<XTypeElement> contributingModule();
+  public abstract Optional<? extends Binding> unresolved();
+
+  /** Returns the optional scope used on the binding. */
+  public abstract Optional<Scope> scope();
 }
diff --git a/java/dagger/internal/codegen/binding/BindingFactory.java b/java/dagger/internal/codegen/binding/BindingFactory.java
index 11fa591..8a57abf 100644
--- a/java/dagger/internal/codegen/binding/BindingFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingFactory.java
@@ -17,29 +17,12 @@
 package dagger.internal.codegen.binding;
 
 import static androidx.room.compiler.processing.XElementKt.isMethod;
-import static androidx.room.compiler.processing.XElementKt.isTypeElement;
 import static androidx.room.compiler.processing.XElementKt.isVariableElement;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentProductionMethod;
-import static dagger.internal.codegen.binding.MapKeys.getMapKey;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.model.BindingKind.ASSISTED_FACTORY;
-import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.internal.codegen.model.BindingKind.BOUND_INSTANCE;
-import static dagger.internal.codegen.model.BindingKind.COMPONENT;
-import static dagger.internal.codegen.model.BindingKind.COMPONENT_DEPENDENCY;
-import static dagger.internal.codegen.model.BindingKind.COMPONENT_PRODUCTION;
-import static dagger.internal.codegen.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.internal.codegen.model.BindingKind.DELEGATE;
-import static dagger.internal.codegen.model.BindingKind.INJECTION;
-import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTOR;
-import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
-import static dagger.internal.codegen.model.BindingKind.PRODUCTION;
-import static dagger.internal.codegen.model.BindingKind.PROVISION;
-import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
 import static dagger.internal.codegen.xprocessing.XElements.asMethod;
 import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
 import static dagger.internal.codegen.xprocessing.XElements.asVariable;
@@ -57,23 +40,18 @@
 import androidx.room.compiler.processing.XVariableElement;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Iterables;
-import com.squareup.javapoet.ClassName;
 import dagger.Module;
-import dagger.internal.codegen.base.ContributionType;
 import dagger.internal.codegen.base.MapType;
+import dagger.internal.codegen.base.OptionalType;
 import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProductionBinding.ProductionKind;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.BindingKind;
-import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.Optional;
-import java.util.function.BiFunction;
 import javax.inject.Inject;
 
 /** A factory for {@link Binding} objects. */
@@ -96,16 +74,16 @@
   }
 
   /**
-   * Returns an {@link dagger.internal.codegen.model.BindingKind#INJECTION} binding.
+   * Returns an {@link BindingKind#INJECTION} binding.
    *
    * @param constructorElement the {@code @Inject}-annotated constructor
-   * @param resolvedType the parameterized type if the constructor is for a generic class and the
-   *     binding should be for the parameterized type
+   * @param resolvedEnclosingType the parameterized type if the constructor is for a generic class
+   *     and the binding should be for the parameterized type
    */
   // TODO(dpb): See if we can just pass the parameterized type and not also the constructor.
-  public ProvisionBinding injectionBinding(
+  public InjectionBinding injectionBinding(
       XConstructorElement constructorElement, Optional<XType> resolvedEnclosingType) {
-    checkArgument(InjectionAnnotations.hasInjectOrAssistedInjectAnnotation(constructorElement));
+    checkArgument(InjectionAnnotations.hasInjectAnnotation(constructorElement));
 
     XConstructorType constructorType = constructorElement.getExecutableType();
     XType enclosingType = constructorElement.getEnclosingElement().getType();
@@ -117,37 +95,74 @@
     }
 
     // Collect all dependency requests within the provision method.
-    // Note: we filter out @Assisted parameters since these aren't considered dependency requests.
-    ImmutableSet.Builder<DependencyRequest> provisionDependencies = ImmutableSet.builder();
+    ImmutableSet.Builder<DependencyRequest> constructorDependencies = ImmutableSet.builder();
     for (int i = 0; i < constructorElement.getParameters().size(); i++) {
       XExecutableParameterElement parameter = constructorElement.getParameters().get(i);
       XType parameterType = constructorType.getParameterTypes().get(i);
+      constructorDependencies.add(
+          dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType));
+    }
+
+    return InjectionBinding.builder()
+        .bindingElement(constructorElement)
+        .key(keyFactory.forInjectConstructorWithResolvedType(enclosingType))
+        .constructorDependencies(constructorDependencies.build())
+        .injectionSites(injectionSiteFactory.getInjectionSites(enclosingType))
+        .scope(injectionAnnotations.getScope(constructorElement.getEnclosingElement()))
+        .unresolved(
+            hasNonDefaultTypeParameters(enclosingType)
+                ? Optional.of(injectionBinding(constructorElement, Optional.empty()))
+                : Optional.empty())
+        .build();
+  }
+
+  /**
+   * Returns an {@link BindingKind#ASSISTED_INJECTION} binding.
+   *
+   * @param constructorElement the {@code @Inject}-annotated constructor
+   * @param resolvedEnclosingType the parameterized type if the constructor is for a generic class
+   *     and the binding should be for the parameterized type
+   */
+  // TODO(dpb): See if we can just pass the parameterized type and not also the constructor.
+  public AssistedInjectionBinding assistedInjectionBinding(
+      XConstructorElement constructorElement, Optional<XType> resolvedEnclosingType) {
+    checkArgument(constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT));
+
+    XConstructorType constructorType = constructorElement.getExecutableType();
+    XType enclosingType = constructorElement.getEnclosingElement().getType();
+    // If the class this is constructing has some type arguments, resolve everything.
+    if (!enclosingType.getTypeArguments().isEmpty() && resolvedEnclosingType.isPresent()) {
+      checkIsSameErasedType(resolvedEnclosingType.get(), enclosingType);
+      enclosingType = resolvedEnclosingType.get();
+      constructorType = constructorElement.asMemberOf(enclosingType);
+    }
+
+    // Collect all dependency requests within the provision method.
+    ImmutableSet.Builder<DependencyRequest> constructorDependencies = ImmutableSet.builder();
+    for (int i = 0; i < constructorElement.getParameters().size(); i++) {
+      XExecutableParameterElement parameter = constructorElement.getParameters().get(i);
+      XType parameterType = constructorType.getParameterTypes().get(i);
+      // Note: we filter out @Assisted parameters since these aren't considered dependency requests.
       if (!AssistedInjectionAnnotations.isAssistedParameter(parameter)) {
-        provisionDependencies.add(
+        constructorDependencies.add(
             dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType));
       }
     }
 
-    ProvisionBinding.Builder builder =
-        ProvisionBinding.builder()
-            .contributionType(ContributionType.UNIQUE)
-            .bindingElement(constructorElement)
-            .key(keyFactory.forInjectConstructorWithResolvedType(enclosingType))
-            .provisionDependencies(provisionDependencies.build())
-            .injectionSites(injectionSiteFactory.getInjectionSites(enclosingType))
-            .kind(
-                constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)
-                    ? ASSISTED_INJECTION
-                    : INJECTION)
-            .scope(injectionAnnotations.getScope(constructorElement.getEnclosingElement()));
-
-    if (hasNonDefaultTypeParameters(enclosingType)) {
-      builder.unresolved(injectionBinding(constructorElement, Optional.empty()));
-    }
-    return builder.build();
+    return AssistedInjectionBinding.builder()
+        .bindingElement(constructorElement)
+        .key(keyFactory.forInjectConstructorWithResolvedType(enclosingType))
+        .constructorDependencies(constructorDependencies.build())
+        .injectionSites(injectionSiteFactory.getInjectionSites(enclosingType))
+        .scope(injectionAnnotations.getScope(constructorElement.getEnclosingElement()))
+        .unresolved(
+            hasNonDefaultTypeParameters(enclosingType)
+                ? Optional.of(assistedInjectionBinding(constructorElement, Optional.empty()))
+                : Optional.empty())
+        .build();
   }
 
-  public ProvisionBinding assistedFactoryBinding(
+  public AssistedFactoryBinding assistedFactoryBinding(
       XTypeElement factory, Optional<XType> resolvedFactoryType) {
 
     // If the class this is constructing has some type arguments, resolve everything.
@@ -159,351 +174,325 @@
 
     XMethodElement factoryMethod = AssistedInjectionAnnotations.assistedFactoryMethod(factory);
     XMethodType factoryMethodType = factoryMethod.asMemberOf(factoryType);
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
+    return AssistedFactoryBinding.builder()
         .key(keyFactory.forType(factoryType))
         .bindingElement(factory)
-        .provisionDependencies(
-            ImmutableSet.of(
-                DependencyRequest.builder()
-                    .key(keyFactory.forType(factoryMethodType.getReturnType()))
-                    .kind(RequestKind.PROVIDER)
-                    .build()))
-        .kind(ASSISTED_FACTORY)
+        .assistedInjectKey(keyFactory.forType(factoryMethodType.getReturnType()))
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#PROVISION} binding for a
-   * {@code @Provides}-annotated method.
+   * Returns a {@link BindingKind#PROVISION} binding for a {@code @Provides}-annotated method.
    *
-   * @param contributedBy the installed module that declares or inherits the method
+   * @param module the installed module that declares or inherits the method
    */
-  public ProvisionBinding providesMethodBinding(
-      XMethodElement providesMethod, XTypeElement contributedBy) {
-    return setMethodBindingProperties(
-            ProvisionBinding.builder(),
-            providesMethod,
-            contributedBy,
-            keyFactory.forProvidesMethod(providesMethod, contributedBy),
-            this::providesMethodBinding)
-        .kind(PROVISION)
-        .scope(injectionAnnotations.getScope(providesMethod))
-        .nullability(Nullability.of(providesMethod))
-        .build();
-  }
-
-  /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#PRODUCTION} binding for a
-   * {@code @Produces}-annotated method.
-   *
-   * @param contributedBy the installed module that declares or inherits the method
-   */
-  public ProductionBinding producesMethodBinding(
-      XMethodElement producesMethod, XTypeElement contributedBy) {
-    // TODO(beder): Add nullability checking with Java 8.
-    ProductionBinding.Builder builder =
-        setMethodBindingProperties(
-                ProductionBinding.builder(),
-                producesMethod,
-                contributedBy,
-                keyFactory.forProducesMethod(producesMethod, contributedBy),
-                this::producesMethodBinding)
-            .kind(PRODUCTION)
-            .productionKind(ProductionKind.fromProducesMethod(producesMethod))
-            .thrownTypes(producesMethod.getThrownTypes())
-            .executorRequest(dependencyRequestFactory.forProductionImplementationExecutor())
-            .monitorRequest(dependencyRequestFactory.forProductionComponentMonitor());
-    return builder.build();
-  }
-
-  private <C extends ContributionBinding, B extends ContributionBinding.Builder<C, B>>
-      B setMethodBindingProperties(
-          B builder,
-          XMethodElement method,
-          XTypeElement contributedBy,
-          Key key,
-          BiFunction<XMethodElement, XTypeElement, C> create) {
-    XMethodType methodType = method.asMemberOf(contributedBy.getType());
-    if (!methodType.isSameType(method.getExecutableType())) {
-      checkState(isTypeElement(method.getEnclosingElement()));
-      builder.unresolved(create.apply(method, asTypeElement(method.getEnclosingElement())));
-    }
-    return builder
-        .contributionType(ContributionType.fromBindingElement(method))
+  public ProvisionBinding providesMethodBinding(XMethodElement method, XTypeElement module) {
+    XMethodType methodType = method.asMemberOf(module.getType());
+    return ProvisionBinding.builder()
+        .scope(injectionAnnotations.getScope(method))
+        .nullability(Nullability.of(method))
         .bindingElement(method)
-        .contributingModule(contributedBy)
-        .key(key)
+        .contributingModule(module)
+        .key(keyFactory.forProvidesMethod(method, module))
         .dependencies(
             dependencyRequestFactory.forRequiredResolvedVariables(
                 method.getParameters(), methodType.getParameterTypes()))
-        .mapKey(getMapKey(method).map(DaggerAnnotation::from));
-  }
-
-  /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#MULTIBOUND_MAP} or {@link
-   * dagger.internal.codegen.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding
-   * contribution bindings.
-   *
-   * @param key a key that may be satisfied by a multibinding
-   */
-  public ContributionBinding syntheticMultibinding(
-      Key key, Iterable<ContributionBinding> multibindingContributions) {
-    ContributionBinding.Builder<?, ?> builder =
-        multibindingRequiresProduction(key, multibindingContributions)
-            ? ProductionBinding.builder()
-            : ProvisionBinding.builder();
-    return builder
-        .contributionType(ContributionType.UNIQUE)
-        .key(key)
-        .dependencies(
-            dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
-        .kind(bindingKindForMultibindingKey(key))
+        .unresolved(
+            methodType.isSameType(method.getExecutableType())
+                ? Optional.empty()
+                : Optional.of(
+                    providesMethodBinding(method, asTypeElement(method.getEnclosingElement()))))
         .build();
   }
 
-  private static BindingKind bindingKindForMultibindingKey(Key key) {
-    if (SetType.isSet(key)) {
-      return BindingKind.MULTIBOUND_SET;
-    } else if (MapType.isMap(key)) {
-      return BindingKind.MULTIBOUND_MAP;
-    } else {
-      throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
-    }
+  /**
+   * Returns a {@link BindingKind#PRODUCTION} binding for a {@code @Produces}-annotated method.
+   *
+   * @param module the installed module that declares or inherits the method
+   */
+  public ProductionBinding producesMethodBinding(XMethodElement method, XTypeElement module) {
+    // TODO(beder): Add nullability checking with Java 8.
+    XMethodType methodType = method.asMemberOf(module.getType());
+    return ProductionBinding.builder()
+        .bindingElement(method)
+        .contributingModule(module)
+        .key(keyFactory.forProducesMethod(method, module))
+        .executorRequest(dependencyRequestFactory.forProductionImplementationExecutor())
+        .monitorRequest(dependencyRequestFactory.forProductionComponentMonitor())
+        .explicitDependencies(
+            dependencyRequestFactory.forRequiredResolvedVariables(
+                method.getParameters(), methodType.getParameterTypes()))
+        .scope(injectionAnnotations.getScope(method))
+        .unresolved(
+            methodType.isSameType(method.getExecutableType())
+                ? Optional.empty()
+                : Optional.of(
+                    producesMethodBinding(method, asTypeElement(method.getEnclosingElement()))))
+        .build();
   }
 
-  private boolean multibindingRequiresProduction(
+  /**
+   * Returns a {@link BindingKind#MULTIBOUND_MAP} binding given a set of multibinding contributions.
+   *
+   * @param key a key that may be satisfied by a multibinding
+   */
+  public MultiboundMapBinding multiboundMap(
+      Key key, Iterable<ContributionBinding> multibindingContributions) {
+    return MultiboundMapBinding.builder()
+        .optionalBindingType(multibindingBindingType(key, multibindingContributions))
+        .key(key)
+        .dependencies(
+            dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
+        .build();
+  }
+
+  /**
+   * Returns a {@link BindingKind#MULTIBOUND_SET} binding given a set of multibinding contributions.
+   *
+   * @param key a key that may be satisfied by a multibinding
+   */
+  public MultiboundSetBinding multiboundSet(
+      Key key, Iterable<ContributionBinding> multibindingContributions) {
+    return MultiboundSetBinding.builder()
+        .optionalBindingType(multibindingBindingType(key, multibindingContributions))
+        .key(key)
+        .dependencies(
+            dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
+        .build();
+  }
+
+  private Optional<BindingType> multibindingBindingType(
       Key key, Iterable<ContributionBinding> multibindingContributions) {
     if (MapType.isMap(key)) {
       MapType mapType = MapType.from(key);
       if (mapType.valuesAreTypeOf(TypeNames.PRODUCER)
           || mapType.valuesAreTypeOf(TypeNames.PRODUCED)) {
-        return true;
+        return Optional.of(BindingType.PRODUCTION);
       }
     } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(TypeNames.PRODUCED)) {
-      return true;
+      return Optional.of(BindingType.PRODUCTION);
+    }
+    if (Iterables.any(
+            multibindingContributions,
+            binding -> binding.optionalBindingType().equals(Optional.of(BindingType.PRODUCTION)))) {
+      return Optional.of(BindingType.PRODUCTION);
     }
     return Iterables.any(
-        multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION));
+            multibindingContributions,
+            binding -> binding.optionalBindingType().isEmpty())
+        // If a dependency is missing a BindingType then we can't determine the BindingType of this
+        // binding yet since it may end up depending on a production type.
+        ? Optional.empty()
+        : Optional.of(BindingType.PROVISION);
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT} binding for the
+   * Returns a {@link BindingKind#COMPONENT} binding for the
    * component.
    */
-  public ProvisionBinding componentBinding(XTypeElement componentDefinitionType) {
+  public ComponentBinding componentBinding(XTypeElement componentDefinitionType) {
     checkNotNull(componentDefinitionType);
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
+    return ComponentBinding.builder()
         .bindingElement(componentDefinitionType)
         .key(keyFactory.forType(componentDefinitionType.getType()))
-        .kind(COMPONENT)
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT_DEPENDENCY} binding for a
+   * Returns a {@link BindingKind#COMPONENT_DEPENDENCY} binding for a
    * component's dependency.
    */
-  public ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) {
+  public ComponentDependencyBinding componentDependencyBinding(ComponentRequirement dependency) {
     checkNotNull(dependency);
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
+    return ComponentDependencyBinding.builder()
         .bindingElement(dependency.typeElement())
         .key(keyFactory.forType(dependency.type()))
-        .kind(COMPONENT_DEPENDENCY)
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT_PROVISION} or {@link
-   * dagger.internal.codegen.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a
-   * component's dependency.
-   *
-   * @param componentDescriptor the component with the dependency, not the dependency that has the
-   *     method
+   * Returns a {@link BindingKind#COMPONENT_PROVISION} binding for a
+   * method on a component's dependency.
    */
-  public ContributionBinding componentDependencyMethodBinding(
-      ComponentDescriptor componentDescriptor, XMethodElement dependencyMethod) {
+  public ComponentDependencyProvisionBinding componentDependencyProvisionMethodBinding(
+      XMethodElement dependencyMethod) {
     checkArgument(dependencyMethod.getParameters().isEmpty());
-    ContributionBinding.Builder<?, ?> builder;
-    if (componentDescriptor.isProduction() && isComponentProductionMethod(dependencyMethod)) {
-      builder =
-          ProductionBinding.builder()
-              .key(keyFactory.forProductionComponentMethod(dependencyMethod))
-              .kind(COMPONENT_PRODUCTION)
-              .thrownTypes(dependencyMethod.getThrownTypes());
-    } else {
-      builder =
-          ProvisionBinding.builder()
-              .key(keyFactory.forComponentMethod(dependencyMethod))
-              .nullability(Nullability.of(dependencyMethod))
-              .kind(COMPONENT_PROVISION)
-              .scope(injectionAnnotations.getScope(dependencyMethod));
-    }
-    return builder
-        .contributionType(ContributionType.UNIQUE)
+    return ComponentDependencyProvisionBinding.builder()
+        .key(keyFactory.forComponentMethod(dependencyMethod))
+        .nullability(Nullability.of(dependencyMethod))
+        .scope(injectionAnnotations.getScope(dependencyMethod))
         .bindingElement(dependencyMethod)
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#BOUND_INSTANCE} binding for a
+   * Returns a {@link BindingKind#COMPONENT_PRODUCTION} binding for a
+   * method on a component's dependency.
+   */
+  public ComponentDependencyProductionBinding componentDependencyProductionMethodBinding(
+      XMethodElement dependencyMethod) {
+    checkArgument(dependencyMethod.getParameters().isEmpty());
+    return ComponentDependencyProductionBinding.builder()
+        .key(keyFactory.forProductionComponentMethod(dependencyMethod))
+        .bindingElement(dependencyMethod)
+        .build();
+  }
+
+  /**
+   * Returns a {@link BindingKind#BOUND_INSTANCE} binding for a
    * {@code @BindsInstance}-annotated builder setter method or factory method parameter.
    */
-  ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, XElement element) {
+  BoundInstanceBinding boundInstanceBinding(ComponentRequirement requirement, XElement element) {
     checkArgument(isVariableElement(element) || isMethod(element));
     XVariableElement parameterElement =
         isVariableElement(element)
             ? asVariable(element)
             : getOnlyElement(asMethod(element).getParameters());
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
+    return BoundInstanceBinding.builder()
         .bindingElement(element)
         .key(requirement.key().get())
         .nullability(Nullability.of(parameterElement))
-        .kind(BOUND_INSTANCE)
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#SUBCOMPONENT_CREATOR} binding
+   * Returns a {@link BindingKind#SUBCOMPONENT_CREATOR} binding
    * declared by a component method that returns a subcomponent builder. Use {{@link
    * #subcomponentCreatorBinding(ImmutableSet)}} for bindings declared using {@link
    * Module#subcomponents()}.
    *
    * @param component the component that declares or inherits the method
    */
-  ProvisionBinding subcomponentCreatorBinding(
+  SubcomponentCreatorBinding subcomponentCreatorBinding(
       XMethodElement subcomponentCreatorMethod, XTypeElement component) {
     checkArgument(subcomponentCreatorMethod.getParameters().isEmpty());
     Key key =
         keyFactory.forSubcomponentCreatorMethod(subcomponentCreatorMethod, component.getType());
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
+    return SubcomponentCreatorBinding.builder()
         .bindingElement(subcomponentCreatorMethod)
         .key(key)
-        .kind(SUBCOMPONENT_CREATOR)
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#SUBCOMPONENT_CREATOR} binding
+   * Returns a {@link BindingKind#SUBCOMPONENT_CREATOR} binding
    * declared using {@link Module#subcomponents()}.
    */
-  ProvisionBinding subcomponentCreatorBinding(
+  SubcomponentCreatorBinding subcomponentCreatorBinding(
       ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
     SubcomponentDeclaration subcomponentDeclaration = subcomponentDeclarations.iterator().next();
-    return ProvisionBinding.builder()
-        .contributionType(ContributionType.UNIQUE)
-        .key(subcomponentDeclaration.key())
-        .kind(SUBCOMPONENT_CREATOR)
-        .build();
+    return SubcomponentCreatorBinding.builder().key(subcomponentDeclaration.key()).build();
+  }
+
+  /** Returns a {@link BindingKind#DELEGATE} binding. */
+  DelegateBinding delegateBinding(DelegateDeclaration delegateDeclaration) {
+    return delegateBinding(delegateDeclaration, Optional.empty());
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#DELEGATE} binding.
+   * Returns a {@link BindingKind#DELEGATE} binding.
    *
    * @param delegateDeclaration the {@code @Binds}-annotated declaration
    * @param actualBinding the binding that satisfies the {@code @Binds} declaration
    */
-  ContributionBinding delegateBinding(
+  DelegateBinding delegateBinding(
       DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding) {
-    switch (actualBinding.bindingType()) {
-      case PRODUCTION:
-        return buildDelegateBinding(
-            ProductionBinding.builder().nullability(actualBinding.nullability()),
-            delegateDeclaration,
-            TypeNames.PRODUCER);
-
-      case PROVISION:
-        return buildDelegateBinding(
-            ProvisionBinding.builder()
-                .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get()))
-                .nullability(actualBinding.nullability()),
-            delegateDeclaration,
-            TypeNames.PROVIDER);
-
-      case MEMBERS_INJECTION: // fall-through to throw
-    }
-    throw new AssertionError("bindingType: " + actualBinding);
+    return delegateBinding(delegateDeclaration, delegateBindingType(Optional.of(actualBinding)));
   }
 
-  /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#DELEGATE} binding used when there is
-   * no binding that satisfies the {@code @Binds} declaration.
-   */
-  public ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
-    return buildDelegateBinding(
-        ProvisionBinding.builder()
-            .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get())),
-        delegateDeclaration,
-        TypeNames.PROVIDER);
-  }
-
-  private ContributionBinding buildDelegateBinding(
-      ContributionBinding.Builder<?, ?> builder,
-      DelegateDeclaration delegateDeclaration,
-      ClassName frameworkType) {
-    return builder
+  private DelegateBinding delegateBinding(
+      DelegateDeclaration delegateDeclaration, Optional<BindingType> optionalBindingType) {
+    return DelegateBinding.builder()
         .contributionType(delegateDeclaration.contributionType())
         .bindingElement(delegateDeclaration.bindingElement().get())
         .contributingModule(delegateDeclaration.contributingModule().get())
-        .key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType))
-        .dependencies(delegateDeclaration.delegateRequest())
-        .mapKey(delegateDeclaration.mapKey())
-        .kind(DELEGATE)
+        .delegateRequest(delegateDeclaration.delegateRequest())
+        .nullability(Nullability.of(delegateDeclaration.bindingElement().get()))
+        .optionalBindingType(optionalBindingType)
+        .key(
+            optionalBindingType.isEmpty()
+                // This is used by BindingGraphFactory which passes in an empty optionalBindingType.
+                // In this case, multibound map contributions will always return the key type
+                // without framework types, i.e. Map<K,V>.
+                ? delegateDeclaration.key()
+                // This is used by LegacyBindingGraphFactory, which passes in a non-empty
+                // optionalBindingType. Then, KeyFactory decides whether or not multibound map
+                // contributions should include the factory type based on the compiler flag,
+                // -Adagger.useFrameworkTypeInMapMultibindingContributionKey.
+                : optionalBindingType.get() == BindingType.PRODUCTION
+                    ? keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PRODUCER)
+                    : keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PROVIDER))
+        .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get()))
         .build();
   }
 
   /**
-   * Returns an {@link dagger.internal.codegen.model.BindingKind#OPTIONAL} binding for {@code key}.
-   *
-   * @param requestKind the kind of request for the optional binding
-   * @param underlyingKeyBindings the possibly empty set of bindings that exist in the component for
-   *     the underlying (non-optional) key
+   * Returns a {@link BindingKind#DELEGATE} binding used when there is
+   * no binding that satisfies the {@code @Binds} declaration.
    */
-  ContributionBinding syntheticOptionalBinding(
-      Key key,
-      RequestKind requestKind,
-      ImmutableCollection<? extends Binding> underlyingKeyBindings) {
-    if (underlyingKeyBindings.isEmpty()) {
-      return ProvisionBinding.builder()
-          .contributionType(ContributionType.UNIQUE)
-          .key(key)
-          .kind(OPTIONAL)
-          .build();
+  public DelegateBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
+    return delegateBinding(delegateDeclaration, Optional.of(BindingType.PROVISION));
+  }
+
+  private Optional<BindingType> delegateBindingType(Optional<ContributionBinding> actualBinding) {
+    if (actualBinding.isEmpty()) {
+      return Optional.empty();
     }
+    checkArgument(actualBinding.get().bindingType() != BindingType.MEMBERS_INJECTION);
+    return Optional.of(actualBinding.get().bindingType());
+  }
 
-    boolean requiresProduction =
-        underlyingKeyBindings.stream()
-                .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION)
-            || requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases
-            || requestKind.equals(RequestKind.PRODUCED); // handles producerFromProvider cases
-
-    return (requiresProduction ? ProductionBinding.builder() : ProvisionBinding.builder())
-        .contributionType(ContributionType.UNIQUE)
+  /** Returns an {@link BindingKind#OPTIONAL} present binding for {@code key}. */
+  OptionalBinding syntheticPresentOptionalDeclaration(
+      Key key, ImmutableCollection<Binding> optionalContributions) {
+    checkArgument(!optionalContributions.isEmpty());
+    return OptionalBinding.builder()
+        .optionalBindingType(presentOptionalBindingType(key, optionalContributions))
         .key(key)
-        .kind(OPTIONAL)
-        .dependencies(dependencyRequestFactory.forSyntheticPresentOptionalBinding(key, requestKind))
+        .delegateRequest(dependencyRequestFactory.forSyntheticPresentOptionalBinding(key))
         .build();
   }
 
-  /** Returns a {@link dagger.internal.codegen.model.BindingKind#MEMBERS_INJECTOR} binding. */
-  public ProvisionBinding membersInjectorBinding(
-      Key key, MembersInjectionBinding membersInjectionBinding) {
-    return ProvisionBinding.builder()
+  private Optional<BindingType> presentOptionalBindingType(
+      Key key, ImmutableCollection<Binding> optionalContributions) {
+    RequestKind requestKind = getRequestKind(OptionalType.from(key).valueType());
+    if (requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases
+            || requestKind.equals(RequestKind.PRODUCED)) { // handles producerFromProvider cases
+      return Optional.of(BindingType.PRODUCTION);
+    }
+    if (optionalContributions.stream()
+            .filter(binding -> binding.optionalBindingType().isPresent())
+            .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION)) {
+      return Optional.of(BindingType.PRODUCTION);
+    }
+    return optionalContributions.stream()
+            .anyMatch(binding -> binding.optionalBindingType().isEmpty())
+        // If a dependency is missing a BindingType then we can't determine the BindingType of this
+        // binding yet since it may end up depending on a production type.
+        ? Optional.empty()
+        : Optional.of(BindingType.PROVISION);
+  }
+
+  /** Returns an {@link BindingKind#OPTIONAL} absent binding for {@code key}. */
+  OptionalBinding syntheticAbsentOptionalDeclaration(Key key) {
+    return OptionalBinding.builder()
         .key(key)
-        .contributionType(ContributionType.UNIQUE)
-        .kind(MEMBERS_INJECTOR)
+        .optionalBindingType(Optional.of(BindingType.PROVISION))
+        .build();
+  }
+
+  /** Returns a {@link BindingKind#MEMBERS_INJECTOR} binding. */
+  public MembersInjectorBinding membersInjectorBinding(
+      Key key, MembersInjectionBinding membersInjectionBinding) {
+    return MembersInjectorBinding.builder()
+        .key(key)
         .bindingElement(membersInjectionBinding.key().type().xprocessing().getTypeElement())
-        .provisionDependencies(membersInjectionBinding.dependencies())
         .injectionSites(membersInjectionBinding.injectionSites())
         .build();
   }
 
   /**
-   * Returns a {@link dagger.internal.codegen.model.BindingKind#MEMBERS_INJECTION} binding.
+   * Returns a {@link BindingKind#MEMBERS_INJECTION} binding.
    *
    * @param resolvedType if {@code declaredType} is a generic class and {@code resolvedType} is a
    *     parameterization of that type, the returned binding will be for the resolved type
@@ -515,20 +504,15 @@
       checkIsSameErasedType(resolvedType.get(), type);
       type = resolvedType.get();
     }
-    ImmutableSortedSet<InjectionSite> injectionSites = injectionSiteFactory.getInjectionSites(type);
-    ImmutableSet<DependencyRequest> dependencies =
-        injectionSites.stream()
-            .flatMap(injectionSite -> injectionSite.dependencies().stream())
-            .collect(toImmutableSet());
-
-    return MembersInjectionBinding.create(
-        keyFactory.forMembersInjectedType(type),
-        dependencies,
-        hasNonDefaultTypeParameters(type)
-            ? Optional.of(
-                membersInjectionBinding(type.getTypeElement().getType(), Optional.empty()))
-            : Optional.empty(),
-        injectionSites);
+    return MembersInjectionBinding.builder()
+        .key(keyFactory.forMembersInjectedType(type))
+        .injectionSites(injectionSiteFactory.getInjectionSites(type))
+        .unresolved(
+            hasNonDefaultTypeParameters(type)
+                ? Optional.of(
+                    membersInjectionBinding(type.getTypeElement().getType(), Optional.empty()))
+                : Optional.empty())
+        .build();
   }
 
   private void checkIsSameErasedType(XType type1, XType type2) {
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
index 0090b3d..9dffac0 100644
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ b/java/dagger/internal/codegen/binding/BindingGraph.java
@@ -17,6 +17,7 @@
 package dagger.internal.codegen.binding;
 
 import static com.google.common.collect.Iterables.transform;
+import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
 import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
@@ -42,6 +43,7 @@
 import com.google.common.graph.ImmutableNetwork;
 import com.google.common.graph.Traverser;
 import dagger.internal.codegen.base.TarjanSCCs;
+import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
 import dagger.internal.codegen.model.BindingGraph.ComponentNode;
 import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
@@ -52,6 +54,7 @@
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -73,8 +76,9 @@
   @AutoValue
   public abstract static class TopLevelBindingGraph
       extends dagger.internal.codegen.model.BindingGraph {
-    static TopLevelBindingGraph create(
-        ImmutableNetwork<Node, Edge> network, boolean isFullBindingGraph) {
+    private static TopLevelBindingGraph create(
+        ImmutableNetwork<Node, Edge> network,
+        boolean isFullBindingGraph) {
       TopLevelBindingGraph topLevelBindingGraph =
           new AutoValue_BindingGraph_TopLevelBindingGraph(network, isFullBindingGraph);
 
@@ -194,8 +198,13 @@
   }
 
   static BindingGraph create(
-      ComponentNode componentNode, TopLevelBindingGraph topLevelBindingGraph) {
-    return create(Optional.empty(), componentNode, topLevelBindingGraph);
+        ImmutableNetwork<Node, Edge> network,
+        boolean isFullBindingGraph) {
+    TopLevelBindingGraph topLevelBindingGraph =
+        TopLevelBindingGraph.create(
+            network,
+            isFullBindingGraph);
+    return create(Optional.empty(), topLevelBindingGraph.rootComponentNode(), topLevelBindingGraph);
   }
 
   private static BindingGraph create(
@@ -278,6 +287,29 @@
     return ((ComponentNodeImpl) componentNode()).componentDescriptor();
   }
 
+  /** Returns all entry point methods for this component. */
+  @Memoized
+  public ImmutableSet<ComponentMethodDescriptor> entryPointMethods() {
+    return componentDescriptor().entryPointMethods().stream()
+        .collect(toImmutableSet());
+  }
+
+  public Optional<ComponentMethodDescriptor> findFirstMatchingComponentMethod(
+      BindingRequest request) {
+    return Optional.ofNullable(firstMatchingComponentMethods().get(request));
+  }
+
+  @Memoized
+  ImmutableMap<BindingRequest, ComponentMethodDescriptor> firstMatchingComponentMethods() {
+    Map<BindingRequest, ComponentMethodDescriptor> componentMethodDescriptorsByRequest =
+        new HashMap<>();
+    for (ComponentMethodDescriptor method : entryPointMethods()) {
+      componentMethodDescriptorsByRequest.putIfAbsent(
+          bindingRequest(method.dependencyRequest().get()), method);
+    }
+    return ImmutableMap.copyOf(componentMethodDescriptorsByRequest);
+  }
+
   /**
    * Returns the {@link ContributionBinding} for the given {@link Key} in this component or {@link
    * Optional#empty()} if one doesn't exist.
diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
index 5034359..a85721e 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
@@ -18,49 +18,47 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Predicates.not;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
-import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
+import static dagger.internal.codegen.binding.LegacyBindingGraphFactory.useLegacyBindingGraphFactory;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static dagger.internal.codegen.extension.DaggerGraphs.unreachableNodes;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
 import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
 import static dagger.internal.codegen.model.BindingKind.DELEGATE;
 import static dagger.internal.codegen.model.BindingKind.INJECTION;
 import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
 import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
 import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
-import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import static java.util.function.Predicate.isEqual;
 
-import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XTypeElement;
-import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimaps;
-import dagger.Reusable;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.NetworkBuilder;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import dagger.internal.codegen.base.Keys;
 import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.OptionalType;
+import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.base.TarjanSCCs;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.MissingBinding;
+import dagger.internal.codegen.model.BindingGraph.Node;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.ComponentPath;
 import dagger.internal.codegen.model.DaggerTypeElement;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
-import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.model.Scope;
-import dagger.internal.codegen.xprocessing.XTypeElements;
 import java.util.ArrayDeque;
-import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -69,37 +67,35 @@
 import java.util.Optional;
 import java.util.Queue;
 import java.util.Set;
+import java.util.stream.Stream;
 import javax.inject.Inject;
-import javax.inject.Singleton;
+import javax.tools.Diagnostic;
 
 /** A factory for {@link BindingGraph} objects. */
-@Singleton
-public final class BindingGraphFactory implements ClearableCache {
-
-  private final XProcessingEnv processingEnv;
+public final class BindingGraphFactory {
+  private final LegacyBindingGraphFactory legacyBindingGraphFactory;
   private final InjectBindingRegistry injectBindingRegistry;
   private final KeyFactory keyFactory;
   private final BindingFactory bindingFactory;
-  private final ModuleDescriptor.Factory moduleDescriptorFactory;
-  private final BindingGraphConverter bindingGraphConverter;
-  private final Map<Key, ImmutableSet<Key>> keysMatchingRequestCache = new HashMap<>();
+  private final BindingNode.Factory bindingNodeFactory;
+  private final ComponentDeclarations.Factory componentDeclarationsFactory;
   private final CompilerOptions compilerOptions;
 
   @Inject
   BindingGraphFactory(
-      XProcessingEnv processingEnv,
+      LegacyBindingGraphFactory legacyBindingGraphFactory,
       InjectBindingRegistry injectBindingRegistry,
       KeyFactory keyFactory,
       BindingFactory bindingFactory,
-      ModuleDescriptor.Factory moduleDescriptorFactory,
-      BindingGraphConverter bindingGraphConverter,
+      BindingNode.Factory bindingNodeFactory,
+      ComponentDeclarations.Factory componentDeclarationsFactory,
       CompilerOptions compilerOptions) {
-    this.processingEnv = processingEnv;
+    this.legacyBindingGraphFactory = legacyBindingGraphFactory;
     this.injectBindingRegistry = injectBindingRegistry;
     this.keyFactory = keyFactory;
     this.bindingFactory = bindingFactory;
-    this.moduleDescriptorFactory = moduleDescriptorFactory;
-    this.bindingGraphConverter = bindingGraphConverter;
+    this.bindingNodeFactory = bindingNodeFactory;
+    this.componentDeclarationsFactory = componentDeclarationsFactory;
     this.compilerOptions = compilerOptions;
   }
 
@@ -111,293 +107,117 @@
    */
   public BindingGraph create(
       ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
-    return bindingGraphConverter.convert(
-        createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph),
+    return useLegacyBindingGraphFactory(compilerOptions, componentDescriptor)
+        ? legacyBindingGraphFactory.create(componentDescriptor, createFullBindingGraph)
+        : createBindingGraph(componentDescriptor, createFullBindingGraph);
+  }
+
+  private BindingGraph createBindingGraph(
+      ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
+    Resolver resolver = new Resolver(componentDescriptor);
+    resolver.resolve(createFullBindingGraph);
+
+    MutableNetwork<Node, Edge> network = resolver.network;
+    if (!createFullBindingGraph) {
+      unreachableNodes(network.asGraph(), resolver.componentNode).forEach(network::removeNode);
+    }
+
+    network = BindingGraphTransformations.withFixedBindingTypes(network);
+    return BindingGraph.create(
+        ImmutableNetwork.copyOf(network),
         createFullBindingGraph);
   }
 
-  private LegacyBindingGraph createLegacyBindingGraph(
-      Optional<Resolver> parentResolver,
-      ComponentDescriptor componentDescriptor,
-      boolean createFullBindingGraph) {
-    ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder();
-    ImmutableSet.Builder<DelegateDeclaration> delegatesBuilder = ImmutableSet.builder();
-    ImmutableSet.Builder<OptionalBindingDeclaration> optionalsBuilder = ImmutableSet.builder();
-
-    if (componentDescriptor.isRealComponent()) {
-      // binding for the component itself
-      explicitBindingsBuilder.add(
-          bindingFactory.componentBinding(componentDescriptor.typeElement()));
-    }
-
-    // Collect Component dependencies.
-    for (ComponentRequirement dependency : componentDescriptor.dependencies()) {
-      explicitBindingsBuilder.add(bindingFactory.componentDependencyBinding(dependency));
-
-      // Within a component dependency, we want to allow the same method to appear multiple
-      // times assuming it is the exact same method. We do this by tracking a set of bindings
-      // we've already added with the binding element removed since that is the only thing
-      // allowed to differ.
-      HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create();
-      XTypeElements.getAllMethods(dependency.typeElement()).stream()
-          // MembersInjection methods aren't "provided" explicitly, so ignore them.
-          .filter(ComponentDescriptor::isComponentContributionMethod)
-          .forEach(
-              method -> {
-                ContributionBinding binding =
-                    bindingFactory.componentDependencyMethodBinding(componentDescriptor, method);
-                if (dedupeBindings.put(
-                    getSimpleName(method),
-                    // Remove the binding element since we know that will be different, but
-                    // everything else we want to be the same to consider it a duplicate.
-                    binding.toBuilder().clearBindingElement().build())) {
-                  explicitBindingsBuilder.add(binding);
-                }
-              });
-    }
-
-    // Collect bindings on the creator.
-    componentDescriptor
-        .creatorDescriptor()
-        .ifPresent(
-            creatorDescriptor ->
-                creatorDescriptor.boundInstanceRequirements().stream()
-                    .map(
-                        requirement ->
-                            bindingFactory.boundInstanceBinding(
-                                requirement, creatorDescriptor.elementForRequirement(requirement)))
-                    .forEach(explicitBindingsBuilder::add));
-
-    componentDescriptor
-        .childComponentsDeclaredByBuilderEntryPoints()
-        .forEach(
-            (builderEntryPoint, childComponent) -> {
-              if (!componentDescriptor
-                  .childComponentsDeclaredByModules()
-                  .contains(childComponent)) {
-                explicitBindingsBuilder.add(
-                    bindingFactory.subcomponentCreatorBinding(
-                        builderEntryPoint.methodElement(), componentDescriptor.typeElement()));
-              }
-            });
-
-    ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations = ImmutableSet.builder();
-    ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder();
-
-    // Collect transitive module bindings and multibinding declarations.
-    ImmutableSet<ModuleDescriptor> modules = modules(componentDescriptor, parentResolver);
-    for (ModuleDescriptor moduleDescriptor : modules) {
-      explicitBindingsBuilder.addAll(moduleDescriptor.bindings());
-      multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations());
-      subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations());
-      delegatesBuilder.addAll(moduleDescriptor.delegateDeclarations());
-      optionalsBuilder.addAll(moduleDescriptor.optionalDeclarations());
-    }
-
-    DaggerTypeElement component = DaggerTypeElement.from(componentDescriptor.typeElement());
-    ComponentPath componentPath =
-        parentResolver.isPresent()
-            ? parentResolver.get().componentPath.childPath(component)
-            : ComponentPath.create(ImmutableList.of(component));
-    final Resolver requestResolver =
-        new Resolver(
-            componentPath,
-            parentResolver,
-            componentDescriptor,
-            indexBindingDeclarationsByKey(explicitBindingsBuilder.build()),
-            indexBindingDeclarationsByKey(multibindingDeclarations.build()),
-            indexBindingDeclarationsByKey(subcomponentDeclarations.build()),
-            indexBindingDeclarationsByKey(delegatesBuilder.build()),
-            indexBindingDeclarationsByKey(optionalsBuilder.build()));
-
-    componentDescriptor.entryPointMethods().stream()
-        .map(method -> method.dependencyRequest().get())
-        .forEach(
-            entryPoint -> {
-              if (entryPoint.kind().equals(MEMBERS_INJECTION)) {
-                requestResolver.resolveMembersInjection(entryPoint.key());
-              } else {
-                requestResolver.resolve(entryPoint.key());
-              }
-            });
-
-    if (createFullBindingGraph) {
-      // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
-      // identifier so that the multibinding itself is resolved.
-      modules.stream()
-          .flatMap(module -> module.allBindingKeys().stream())
-          .map(Key::withoutMultibindingContributionIdentifier)
-          .forEach(requestResolver::resolve);
-    }
-
-    // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
-    // been detected during binding resolution. If a binding for a subcomponent is never resolved,
-    // no BindingGraph will be created for it and no implementation will be generated. This is
-    // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
-    // from a parent graph. This is done until no more new subcomponents are resolved.
-    Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
-    ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder();
-    for (ComponentDescriptor subcomponent :
-        Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) {
-      if (resolvedSubcomponents.add(subcomponent)) {
-        subgraphs.add(
-            createLegacyBindingGraph(
-                Optional.of(requestResolver), subcomponent, createFullBindingGraph));
-      }
-    }
-
-    return new LegacyBindingGraph(requestResolver, subgraphs.build());
-  }
-
-  /**
-   * Returns all the modules that should be installed in the component. For production components
-   * and production subcomponents that have a parent that is not a production component or
-   * subcomponent, also includes the production monitoring module for the component and the
-   * production executor module.
-   */
-  private ImmutableSet<ModuleDescriptor> modules(
-      ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) {
-    return shouldIncludeImplicitProductionModules(componentDescriptor, parentResolver)
-        ? new ImmutableSet.Builder<ModuleDescriptor>()
-            .addAll(componentDescriptor.modules())
-            .add(
-                moduleDescriptorFactory.create(
-                    DaggerSuperficialValidation.requireTypeElement(
-                        processingEnv,
-                        generatedMonitoringModuleName(componentDescriptor.typeElement()))))
-            .add(
-                moduleDescriptorFactory.create(
-                    processingEnv.requireTypeElement(TypeNames.PRODUCTION_EXECTUTOR_MODULE)))
-            .build()
-        : componentDescriptor.modules();
-  }
-
-  private boolean shouldIncludeImplicitProductionModules(
-      ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) {
-    return componentDescriptor.isProduction()
-        && componentDescriptor.isRealComponent()
-        && (parentResolver.isEmpty() || !parentResolver.get().componentDescriptor.isProduction());
-  }
-
-  /** Indexes {@code bindingDeclarations} by {@link BindingDeclaration#key()}. */
-  private static <T extends BindingDeclaration>
-      ImmutableSetMultimap<Key, T> indexBindingDeclarationsByKey(Iterable<T> declarations) {
-    return ImmutableSetMultimap.copyOf(Multimaps.index(declarations, BindingDeclaration::key));
-  }
-
-  @Override
-  public void clearCache() {
-    keysMatchingRequestCache.clear();
-  }
-
-  /** Represents a fully resolved binding graph. */
-  static final class LegacyBindingGraph {
-    private final Resolver resolver;
-    private final ImmutableList<LegacyBindingGraph> resolvedSubgraphs;
-    private final ComponentNode componentNode;
-
-    LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs) {
-      this.resolver = resolver;
-      this.resolvedSubgraphs = resolvedSubgraphs;
-      this.componentNode =
-          ComponentNodeImpl.create(resolver.componentPath, resolver.componentDescriptor);
-    }
-
-    /** Returns the {@link ComponentNode} associated with this binding graph. */
-    ComponentNode componentNode() {
-      return componentNode;
-    }
-
-    /** Returns the {@link ComponentPath} associated with this binding graph. */
-    ComponentPath componentPath() {
-      return resolver.componentPath;
-    }
-
-    /** Returns the {@link ComponentDescriptor} associated with this binding graph. */
-    ComponentDescriptor componentDescriptor() {
-      return resolver.componentDescriptor;
-    }
-
-    /**
-     * Returns the {@link ResolvedBindings} in this graph or a parent graph that matches the given
-     * request.
-     *
-     * <p>An exception is thrown if there are no resolved bindings found for the request; however,
-     * this should never happen since all dependencies should have been resolved at this point.
-     */
-    ResolvedBindings resolvedBindings(BindingRequest request) {
-      return request.isRequestKind(RequestKind.MEMBERS_INJECTION)
-          ? resolver.getResolvedMembersInjectionBindings(request.key())
-          : resolver.getResolvedContributionBindings(request.key());
-    }
-
-    /**
-     * Returns all {@link ResolvedBindings} for the given request.
-     *
-     * <p>Note that this only returns the bindings resolved in this component. Bindings resolved in
-     * parent components are not included.
-     */
-    Iterable<ResolvedBindings> resolvedBindings() {
-      // Don't return an immutable collection - this is only ever used for looping over all bindings
-      // in the graph. Copying is wasteful, especially if is a hashing collection, since the values
-      // should all, by definition, be distinct.
-      return Iterables.concat(
-          resolver.resolvedMembersInjectionBindings.values(),
-          resolver.resolvedContributionBindings.values());
-    }
-
-    /** Returns the resolved subgraphs. */
-    ImmutableList<LegacyBindingGraph> subgraphs() {
-      return resolvedSubgraphs;
-    }
-  }
-
   private final class Resolver {
     final ComponentPath componentPath;
     final Optional<Resolver> parentResolver;
+    final ComponentNode componentNode;
     final ComponentDescriptor componentDescriptor;
-    final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings;
-    final ImmutableSet<ContributionBinding> explicitBindingsSet;
-    final ImmutableSetMultimap<Key, ContributionBinding> explicitMultibindings;
-    final ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations;
-    final ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations;
-    final ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations;
-    final ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations;
-    final ImmutableSetMultimap<Key, DelegateDeclaration> delegateMultibindingDeclarations;
+    final ComponentDeclarations declarations;
+    final MutableNetwork<Node, Edge> network;
     final Map<Key, ResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>();
     final Map<Key, ResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>();
-    final Deque<Key> cycleStack = new ArrayDeque<>();
-    final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>();
-    final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>();
+    final RequiresResolutionChecker requiresResolutionChecker = new RequiresResolutionChecker();
     final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>();
 
-    Resolver(
-        ComponentPath componentPath,
-        Optional<Resolver> parentResolver,
-        ComponentDescriptor componentDescriptor,
-        ImmutableSetMultimap<Key, ContributionBinding> explicitBindings,
-        ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations,
-        ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations,
-        ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations,
-        ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations) {
-      this.componentPath = componentPath;
+    Resolver(ComponentDescriptor componentDescriptor) {
+      this(Optional.empty(), componentDescriptor);
+    }
+
+    Resolver(Resolver parentResolver, ComponentDescriptor componentDescriptor) {
+      this(Optional.of(parentResolver), componentDescriptor);
+    }
+
+    private Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
       this.parentResolver = parentResolver;
       this.componentDescriptor = checkNotNull(componentDescriptor);
-      this.explicitBindings = checkNotNull(explicitBindings);
-      this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values());
-      this.multibindingDeclarations = checkNotNull(multibindingDeclarations);
-      this.subcomponentDeclarations = checkNotNull(subcomponentDeclarations);
-      this.delegateDeclarations = checkNotNull(delegateDeclarations);
-      this.optionalBindingDeclarations = checkNotNull(optionalBindingDeclarations);
-      this.explicitMultibindings = multibindingContributionsByMultibindingKey(explicitBindingsSet);
-      this.delegateMultibindingDeclarations =
-          multibindingContributionsByMultibindingKey(delegateDeclarations.values());
+      DaggerTypeElement componentType = DaggerTypeElement.from(componentDescriptor.typeElement());
+      componentPath =
+          parentResolver.isPresent()
+              ? parentResolver.get().componentPath.childPath(componentType)
+              : ComponentPath.create(ImmutableList.of(componentType));
+      this.componentNode = ComponentNodeImpl.create(componentPath, componentDescriptor);
+      this.network =
+          parentResolver.isPresent()
+              ? parentResolver.get().network
+              : NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
+      declarations =
+          componentDeclarationsFactory.create(
+              parentResolver.map(parent -> parent.componentDescriptor),
+              componentDescriptor);
       subcomponentsToResolve.addAll(
           componentDescriptor.childComponentsDeclaredByFactoryMethods().values());
       subcomponentsToResolve.addAll(
           componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values());
     }
 
+    void resolve(boolean createFullBindingGraph) {
+      addNode(componentNode);
+
+      componentDescriptor.entryPointMethods().stream()
+          .map(method -> method.dependencyRequest().get())
+          .forEach(
+              entryPoint -> {
+                ResolvedBindings resolvedBindings =
+                    entryPoint.kind().equals(MEMBERS_INJECTION)
+                        ? resolveMembersInjectionKey(entryPoint.key())
+                        : resolveContributionKey(entryPoint.key());
+                addDependencyEdges(componentNode, resolvedBindings, entryPoint);
+              });
+
+      if (createFullBindingGraph) {
+        // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
+        // identifier so that the multibinding itself is resolved.
+        declarations.allDeclarations().stream()
+            // TODO(b/349155899): Consider resolving all declarations in full binding graph mode,
+            // not just those from modules.
+            .filter(declaration -> declaration.contributingModule().isPresent())
+            // @BindsOptionalOf bindings are keyed by the unwrapped type so wrap it in Optional to
+            // resolve the optional type instead.
+            .map(
+                declaration ->
+                    declaration instanceof OptionalBindingDeclaration
+                        ? keyFactory.optionalOf(declaration.key())
+                        : declaration.key())
+            .map(Key::withoutMultibindingContributionIdentifier)
+            .forEach(this::resolveContributionKey);
+      }
+
+      // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
+      // been detected during binding resolution. If a binding for a subcomponent is never resolved,
+      // no BindingGraph will be created for it and no implementation will be generated. This is
+      // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
+      // from a parent graph. This is done until no more new subcomponents are resolved.
+      Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
+      for (ComponentDescriptor subcomponent : Iterables.consumingIterable(subcomponentsToResolve)) {
+        if (resolvedSubcomponents.add(subcomponent)) {
+          Resolver subcomponentResolver = new Resolver(this, subcomponent);
+          addChildFactoryMethodEdge(subcomponentResolver);
+          subcomponentResolver.resolve(createFullBindingGraph);
+        }
+      }
+    }
+
     /**
      * Returns the resolved contribution bindings for the given {@link Key}:
      *
@@ -421,38 +241,42 @@
       Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>();
 
       // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions.
-      ImmutableSet<Key> keysMatchingRequest = keysMatchingRequest(requestKey);
       for (Resolver resolver : getResolverLineage()) {
         bindings.addAll(resolver.getLocalExplicitBindings(requestKey));
-
-        for (Key key : keysMatchingRequest) {
-          multibindingContributions.addAll(resolver.getLocalExplicitMultibindings(key));
-          multibindingDeclarations.addAll(resolver.multibindingDeclarations.get(key));
-          subcomponentDeclarations.addAll(resolver.subcomponentDeclarations.get(key));
-          // The optional binding declarations are keyed by the unwrapped type.
-          keyFactory.unwrapOptional(key)
-              .map(resolver.optionalBindingDeclarations::get)
-              .ifPresent(optionalBindingDeclarations::addAll);
-        }
+        multibindingContributions.addAll(resolver.getLocalMultibindingContributions(requestKey));
+        multibindingDeclarations.addAll(resolver.declarations.multibindings(requestKey));
+        subcomponentDeclarations.addAll(resolver.declarations.subcomponents(requestKey));
+        // The optional binding declarations are keyed by the unwrapped type.
+        keyFactory.unwrapOptional(requestKey)
+            .map(resolver.declarations::optionalBindings)
+            .ifPresent(optionalBindingDeclarations::addAll);
       }
 
       // Add synthetic multibinding
       if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) {
-        bindings.add(bindingFactory.syntheticMultibinding(requestKey, multibindingContributions));
+        if (MapType.isMap(requestKey)) {
+          bindings.add(bindingFactory.multiboundMap(requestKey, multibindingContributions));
+        } else if (SetType.isSet(requestKey)) {
+          bindings.add(bindingFactory.multiboundSet(requestKey, multibindingContributions));
+        } else {
+          throw new AssertionError("Unexpected type in multibinding key: " + requestKey);
+        }
       }
 
       // Add synthetic optional binding
       if (!optionalBindingDeclarations.isEmpty()) {
+        ImmutableSet<Binding> optionalContributions =
+            lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings();
         bindings.add(
-            bindingFactory.syntheticOptionalBinding(
-                requestKey,
-                getRequestKind(OptionalType.from(requestKey).valueType()),
-                lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings()));
+            optionalContributions.isEmpty()
+                ? bindingFactory.syntheticAbsentOptionalDeclaration(requestKey)
+                : bindingFactory.syntheticPresentOptionalDeclaration(
+                    requestKey, optionalContributions));
       }
 
       // Add subcomponent creator binding
       if (!subcomponentDeclarations.isEmpty()) {
-        ProvisionBinding binding =
+        ContributionBinding binding =
             bindingFactory.subcomponentCreatorBinding(
                 ImmutableSet.copyOf(subcomponentDeclarations));
         bindings.add(binding);
@@ -461,9 +285,7 @@
 
       // Add members injector binding
       if (isTypeOf(requestKey.type().xprocessing(), TypeNames.MEMBERS_INJECTOR)) {
-        injectBindingRegistry
-            .getOrFindMembersInjectorProvisionBinding(requestKey)
-            .ifPresent(bindings::add);
+        injectBindingRegistry.getOrFindMembersInjectorBinding(requestKey).ifPresent(bindings::add);
       }
 
       // Add Assisted Factory binding
@@ -478,18 +300,32 @@
       // If there are no bindings, add the implicit @Inject-constructed binding if there is one.
       if (bindings.isEmpty()) {
         injectBindingRegistry
-            .getOrFindProvisionBinding(requestKey)
+            .getOrFindInjectionBinding(requestKey)
             .filter(this::isCorrectlyScopedInSubcomponent)
             .ifPresent(bindings::add);
       }
 
-      return ResolvedBindings.forContributionBindings(
-          componentPath,
+      return ResolvedBindings.create(
           requestKey,
-          Multimaps.index(bindings, binding -> getOwningComponent(requestKey, binding)),
-          multibindingDeclarations,
-          subcomponentDeclarations,
-          optionalBindingDeclarations);
+          bindings.stream()
+              .map(
+                  binding -> {
+                    Optional<BindingNode> bindingNodeOwnedByAncestor =
+                        getBindingNodeOwnedByAncestor(requestKey, binding);
+                    // If a binding is owned by an ancestor we use the corresponding BindingNode
+                    // instance directly rather than creating a new instance to avoid accidentally
+                    // including additional multi/optional/subcomponent declarations that don't
+                    // exist in the ancestor's BindingNode instance.
+                    return bindingNodeOwnedByAncestor.isPresent()
+                          ? bindingNodeOwnedByAncestor.get()
+                          : bindingNodeFactory.forContributionBindings(
+                              componentPath,
+                              binding,
+                              multibindingDeclarations,
+                              optionalBindingDeclarations,
+                              subcomponentDeclarations);
+                  })
+              .collect(toImmutableSet()));
     }
 
     /**
@@ -499,7 +335,7 @@
      * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped
      * binding error at the root component).
      */
-    private boolean isCorrectlyScopedInSubcomponent(ProvisionBinding binding) {
+    private boolean isCorrectlyScopedInSubcomponent(ContributionBinding binding) {
       checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION);
       if (!rootComponent().isSubcomponent()
           || !binding.scope().isPresent()
@@ -522,9 +358,10 @@
       Optional<MembersInjectionBinding> binding =
           injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey);
       return binding.isPresent()
-          ? ResolvedBindings.forMembersInjectionBinding(
-              componentPath, requestKey, componentDescriptor, binding.get())
-          : ResolvedBindings.noBindings(componentPath, requestKey);
+          ? ResolvedBindings.create(
+              requestKey,
+              bindingNodeFactory.forMembersInjectionBinding(componentPath, binding.get()))
+          : ResolvedBindings.create(requestKey);
     }
 
     /**
@@ -532,7 +369,7 @@
      * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue
      * will be used to detect which subcomponents need to be resolved.
      */
-    private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding) {
+    private void addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding) {
       checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
       Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
 
@@ -542,126 +379,51 @@
           owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
     }
 
-    /**
-     * Profiling has determined that computing the keys matching {@code requestKey} has measurable
-     * performance impact. It is called repeatedly (at least 3 times per key resolved per {@link
-     * BindingGraph}. {@code javac}'s name-checking performance seems suboptimal (converting byte
-     * strings to Strings repeatedly), and the matching keys creations relies on that. This also
-     * ensures that the resulting keys have their hash codes cached on successive calls to this
-     * method.
-     *
-     * <p>This caching may become obsolete if:
-     *
-     * <ul>
-     *   <li>We decide to intern all {@link Key} instances
-     *   <li>We fix javac's name-checking peformance (though we may want to keep this for older
-     *       javac users)
-     * </ul>
-     */
-    private ImmutableSet<Key> keysMatchingRequest(Key requestKey) {
-      return keysMatchingRequestCache.computeIfAbsent(
-          requestKey, this::keysMatchingRequestUncached);
-    }
-
-    private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) {
-      ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
-      keys.add(requestKey);
-      keyFactory.unwrapSetKey(requestKey, TypeNames.PRODUCED).ifPresent(keys::add);
-      keyFactory
-          .rewrapMapKey(requestKey, TypeNames.PRODUCER, TypeNames.PROVIDER)
-          .ifPresent(keys::add);
-      keyFactory
-          .rewrapMapKey(requestKey, TypeNames.PROVIDER, TypeNames.PRODUCER)
-          .ifPresent(keys::add);
-      keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey));
-      return keys.build();
-    }
-
     private ImmutableSet<ContributionBinding> createDelegateBindings(
         ImmutableSet<DelegateDeclaration> delegateDeclarations) {
       ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
       for (DelegateDeclaration delegateDeclaration : delegateDeclarations) {
-        builder.add(createDelegateBinding(delegateDeclaration));
+        builder.add(bindingFactory.delegateBinding(delegateDeclaration));
       }
       return builder.build();
     }
-
     /**
-     * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved
-     * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate
-     * bindings for the dependency key, there should still be only one binding for the delegate key.
+     * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component,
+     * if one exists. Otherwise returns {@link Optional#empty()}.
      */
-    private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) {
-      Key delegateKey = delegateDeclaration.delegateRequest().key();
-      if (cycleStack.contains(delegateKey)) {
-        return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
+    private Optional<BindingNode> getBindingNodeOwnedByAncestor(
+        Key requestKey, ContributionBinding binding) {
+      if (canBeResolvedInParent(requestKey, binding)) {
+        // Resolve in the parent to make sure we have the most recent multi/optional contributions.
+        parentResolver.get().resolveContributionKey(requestKey);
+        BindingNode previouslyResolvedBinding =
+            getPreviouslyResolvedBindings(requestKey).get().forBinding(binding);
+        if (!requiresResolutionChecker.requiresResolution(previouslyResolvedBinding)) {
+          return Optional.of(previouslyResolvedBinding);
+        }
       }
-
-      ResolvedBindings resolvedDelegate;
-      try {
-        cycleStack.push(delegateKey);
-        resolvedDelegate = lookUpBindings(delegateKey);
-      } finally {
-        cycleStack.pop();
-      }
-      if (resolvedDelegate.contributionBindings().isEmpty()) {
-        // This is guaranteed to result in a missing binding error, so it doesn't matter if the
-        // binding is a Provision or Production, except if it is a @IntoMap method, in which
-        // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a
-        // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a
-        // strange error, that the RHS needs to be provided with an @Inject or @Provides
-        // annotated method, but a user should be able to figure out if a @Produces annotation
-        // is needed.
-        // TODO(gak): revisit how we model missing delegates if/when we clean up how we model
-        // binding declarations
-        return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
-      }
-      // It doesn't matter which of these is selected, since they will later on produce a
-      // duplicate binding error.
-      ContributionBinding explicitDelegate =
-          resolvedDelegate.contributionBindings().iterator().next();
-      return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate);
+      return Optional.empty();
     }
 
-    /**
-     * Returns the component that should contain the framework field for {@code binding}.
-     *
-     * <p>If {@code binding} is either not bound in an ancestor component or depends transitively on
-     * bindings in this component, returns this component.
-     *
-     * <p>Otherwise, resolves {@code request} in this component's parent in order to resolve any
-     * multibinding contributions in the parent, and returns the parent-resolved {@link
-     * ResolvedBindings#owningComponent(ContributionBinding)}.
-     */
-    private XTypeElement getOwningComponent(Key requestKey, ContributionBinding binding) {
-      if (isResolvedInParent(requestKey, binding) && !requiresResolution(binding)) {
-        ResolvedBindings parentResolvedBindings =
-            parentResolver.get().resolvedContributionBindings.get(requestKey);
-        return parentResolvedBindings.owningComponent(binding);
-      } else {
-        return componentDescriptor.typeElement();
-      }
-    }
-
-    /**
-     * Returns {@code true} if {@code binding} is owned by an ancestor. If so, {@linkplain #resolve
-     * resolves} the {@link Key} in this component's parent. Don't resolve directly in the owning
-     * component in case it depends on multibindings in any of its descendants.
-     */
-    private boolean isResolvedInParent(Key requestKey, ContributionBinding binding) {
-      Optional<Resolver> owningResolver = getOwningResolver(binding);
-      if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
-        parentResolver.get().resolve(requestKey);
-        return true;
-      } else {
+    private boolean canBeResolvedInParent(Key requestKey, ContributionBinding binding) {
+      if (parentResolver.isEmpty()) {
         return false;
       }
+      Optional<Resolver> owningResolver = getOwningResolver(binding);
+      if (owningResolver.isPresent()) {
+        return !owningResolver.get().equals(this);
+      }
+      return !Keys.isComponentOrCreator(requestKey)
+          // TODO(b/305748522): Allow caching for assisted injection bindings.
+          && binding.kind() != BindingKind.ASSISTED_INJECTION
+          && getPreviouslyResolvedBindings(requestKey).isPresent()
+          && getPreviouslyResolvedBindings(requestKey).get().bindings().contains(binding);
     }
 
     private Optional<Resolver> getOwningResolver(ContributionBinding binding) {
       // TODO(ronshapiro): extract the different pieces of this method into their own methods
       if ((binding.scope().isPresent() && binding.scope().get().isProductionScope())
-          || binding.bindingType().equals(BindingType.PRODUCTION)) {
+          || binding.kind().equals(BindingKind.PRODUCTION)) {
         for (Resolver requestResolver : getResolverLineage()) {
           // Resolve @Inject @ProductionScope bindings at the highest production component.
           if (binding.kind().equals(INJECTION)
@@ -682,8 +444,7 @@
           // If a @Reusable binding was resolved in an ancestor, use that component.
           ResolvedBindings resolvedBindings =
               requestResolver.resolvedContributionBindings.get(binding.key());
-          if (resolvedBindings != null
-              && resolvedBindings.contributionBindings().contains(binding)) {
+          if (resolvedBindings != null && resolvedBindings.bindings().contains(binding)) {
             return Optional.of(requestResolver);
           }
         }
@@ -691,6 +452,9 @@
         return Optional.empty();
       }
 
+      // TODO(b/359893922): we currently iterate from child to parent to find an owning resolver,
+      // but we probably want to iterate from parent to child to catch missing bindings in
+      // misconfigured repeated modules.
       for (Resolver requestResolver : getResolverLineage().reverse()) {
         if (requestResolver.containsExplicitBinding(binding)) {
           return Optional.of(requestResolver);
@@ -711,9 +475,9 @@
     }
 
     private boolean containsExplicitBinding(ContributionBinding binding) {
-      return explicitBindingsSet.contains(binding)
+      return declarations.bindings(binding.key()).contains(binding)
           || resolverContainsDelegateDeclarationForBinding(binding)
-          || subcomponentDeclarations.containsKey(binding.key());
+          || !declarations.subcomponents(binding.key()).isEmpty();
     }
 
     /** Returns true if {@code binding} was installed in a module in this resolver's component. */
@@ -721,18 +485,10 @@
       if (!binding.kind().equals(DELEGATE)) {
         return false;
       }
-
-      // Map multibinding key values are wrapped with a framework type. This needs to be undone
-      // to look it up in the delegate declarations map.
-      // TODO(erichang): See if we can standardize the way map keys are used in these data
-      // structures, either always wrapped or unwrapped to be consistent and less errorprone.
-      Key bindingKey = binding.key();
-      if (compilerOptions.strictMultibindingValidation()
-          && binding.contributionType().equals(ContributionType.MAP)) {
-        bindingKey = keyFactory.unwrapMapValueType(bindingKey);
+      if (LegacyBindingGraphFactory.hasStrictMultibindingsExemption(compilerOptions, binding)) {
+        return false;
       }
-
-      return delegateDeclarations.get(bindingKey).stream()
+      return declarations.delegates(binding.key()).stream()
           .anyMatch(
               declaration ->
                   declaration.contributingModule().equals(binding.contributingModule())
@@ -755,15 +511,9 @@
      * resolver.
      */
     private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) {
-      return new ImmutableSet.Builder<ContributionBinding>()
-          .addAll(explicitBindings.get(key))
-          // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
-          // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
-          // value type if it's a Map<K, Provider/Producer<V>> before looking in
-          // delegateDeclarations. createDelegateBindings() will create bindings with the properly
-          // wrapped key type.
-          .addAll(
-              createDelegateBindings(delegateDeclarations.get(keyFactory.unwrapMapValueType(key))))
+      return ImmutableSet.<ContributionBinding>builder()
+          .addAll(declarations.bindings(key))
+          .addAll(createDelegateBindings(declarations.delegates(key)))
           .build();
     }
 
@@ -771,22 +521,11 @@
      * Returns the explicit multibinding contributions that contribute to the map or set requested
      * by {@code key} from this resolver.
      */
-    private ImmutableSet<ContributionBinding> getLocalExplicitMultibindings(Key key) {
-      ImmutableSet.Builder<ContributionBinding> multibindings = ImmutableSet.builder();
-      multibindings.addAll(explicitMultibindings.get(key));
-      if (!MapType.isMap(key)
-          || MapType.from(key).isRawType()
-          || MapType.from(key).valuesAreFrameworkType()) {
-        // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
-        // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
-        // value type if it's a Map<K, Provider/Producer<V>> before looking in
-        // delegateMultibindingDeclarations. createDelegateBindings() will create bindings with the
-        // properly wrapped key type.
-        multibindings.addAll(
-            createDelegateBindings(
-                delegateMultibindingDeclarations.get(keyFactory.unwrapMapValueType(key))));
-      }
-      return multibindings.build();
+    private ImmutableSet<ContributionBinding> getLocalMultibindingContributions(Key key) {
+      return ImmutableSet.<ContributionBinding>builder()
+          .addAll(declarations.multibindingContributions(key))
+          .addAll(createDelegateBindings(declarations.delegateMultibindingContributions(key)))
+          .build();
     }
 
     /**
@@ -795,12 +534,12 @@
      */
     private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) {
       Optional<Key> unwrapped = keyFactory.unwrapOptional(key);
-      if (!unwrapped.isPresent()) {
+      if (unwrapped.isEmpty()) {
         return ImmutableSet.of();
       }
       ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder();
       for (Resolver resolver : getResolverLineage()) {
-        declarations.addAll(resolver.optionalBindingDeclarations.get(unwrapped.get()));
+        declarations.addAll(resolver.declarations.optionalBindings(unwrapped.get()));
       }
       return declarations.build();
     }
@@ -811,242 +550,330 @@
      * MembersInjectionBinding}s are not inherited.
      */
     private Optional<ResolvedBindings> getPreviouslyResolvedBindings(Key key) {
-      Optional<ResolvedBindings> result =
-          Optional.ofNullable(resolvedContributionBindings.get(key));
-      if (result.isPresent()) {
-        return result;
-      } else if (parentResolver.isPresent()) {
-        return parentResolver.get().getPreviouslyResolvedBindings(key);
-      } else {
+      if (parentResolver.isEmpty()) {
         return Optional.empty();
       }
+      // Check the parent's resolvedContributionBindings directly before calling
+      // parentResolver.getPreviouslyResolvedBindings() otherwise the parent will skip itself.
+      return parentResolver.get().resolvedContributionBindings.containsKey(key)
+          ? Optional.of(parentResolver.get().resolvedContributionBindings.get(key))
+          : parentResolver.get().getPreviouslyResolvedBindings(key);
     }
 
-    private void resolveMembersInjection(Key key) {
+    private ResolvedBindings resolveMembersInjectionKey(Key key) {
+      if (resolvedMembersInjectionBindings.containsKey(key)) {
+        return resolvedMembersInjectionBindings.get(key);
+      }
       ResolvedBindings bindings = lookUpMembersInjectionBinding(key);
+      addNodes(bindings);
       resolveDependencies(bindings);
       resolvedMembersInjectionBindings.put(key, bindings);
+      return bindings;
     }
 
-    void resolve(Key key) {
-      // If we find a cycle, stop resolving. The original request will add it with all of the
-      // other resolved deps.
-      if (cycleStack.contains(key)) {
-        return;
-      }
-
-      // If the binding was previously resolved in this (sub)component, don't resolve it again.
-      if (resolvedContributionBindings.containsKey(key)) {
-        return;
-      }
-
-      /*
-       * If the binding was previously resolved in an ancestor component, then we may be able to
-       * avoid resolving it here and just depend on the ancestor component resolution.
-       *
-       * 1. If it depends transitively on multibinding contributions or optional bindings with
-       *    bindings from this subcomponent, then we have to resolve it in this subcomponent so
-       *    that it sees the local bindings.
-       *
-       * 2. If there are any explicit bindings in this component, they may conflict with those in
-       *    the ancestor component, so resolve them here so that conflicts can be caught.
-       */
-      if (getPreviouslyResolvedBindings(key).isPresent() && !Keys.isComponentOrCreator(key)) {
-        /* Resolve in the parent in case there are multibinding contributions or conflicts in some
-         * component between this one and the previously-resolved one. */
-        parentResolver.get().resolve(key);
-        ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get();
-        // TODO(b/305748522): Allow caching for assisted injection bindings.
-        boolean isAssistedInjectionBinding =
-            previouslyResolvedBindings.bindings().stream()
-                .anyMatch(binding -> binding.kind() == BindingKind.ASSISTED_INJECTION);
-        if (!isAssistedInjectionBinding
-                && !requiresResolution(key)
-                && getLocalExplicitBindings(key).isEmpty()) {
-          /* Cache the inherited parent component's bindings in case resolving at the parent found
-           * bindings in some component between this one and the previously-resolved one. */
-          resolvedContributionBindings.put(key, previouslyResolvedBindings);
-          return;
-        }
-      }
-
-      cycleStack.push(key);
-      try {
-        ResolvedBindings bindings = lookUpBindings(key);
-        resolvedContributionBindings.put(key, bindings);
-        resolveDependencies(bindings);
-      } finally {
-        cycleStack.pop();
-      }
-    }
-
-    /**
-     * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this
-     * component.
-     */
-    private void resolveDependencies(ResolvedBindings resolvedBindings) {
-      for (Binding binding : resolvedBindings.bindingsOwnedBy(componentDescriptor)) {
-        for (DependencyRequest dependency : binding.dependencies()) {
-          resolve(dependency.key());
-        }
-      }
-    }
-
-    private ResolvedBindings getResolvedContributionBindings(Key key) {
+    @CanIgnoreReturnValue
+    private ResolvedBindings resolveContributionKey(Key key) {
       if (resolvedContributionBindings.containsKey(key)) {
         return resolvedContributionBindings.get(key);
       }
-      if (parentResolver.isPresent()) {
-        return parentResolver.get().getResolvedContributionBindings(key);
+      ResolvedBindings bindings = lookUpBindings(key);
+      resolvedContributionBindings.put(key, bindings);
+      addNodes(bindings);
+      resolveDependencies(bindings);
+      return bindings;
+    }
+
+     /** Resolves each of the dependencies of the bindings owned by this component. */
+    private void resolveDependencies(ResolvedBindings resolvedBindings) {
+      for (BindingNode binding : resolvedBindings.bindingNodesOwnedBy(componentPath)) {
+        for (DependencyRequest request : binding.dependencies()) {
+          ResolvedBindings dependencies = resolveContributionKey(request.key());
+          addDependencyEdges(binding, dependencies, request);
+        }
       }
-      throw new AssertionError("No resolved bindings for key: " + key);
     }
 
-    private ResolvedBindings getResolvedMembersInjectionBindings(Key key) {
-      return resolvedMembersInjectionBindings.get(key);
+    private void addNodes(ResolvedBindings resolvedBindings) {
+      if (resolvedBindings.isEmpty()) {
+        addNode(missingBinding(resolvedBindings.key()));
+        return;
+      }
+      resolvedBindings.bindingNodesOwnedBy(componentPath).forEach(this::addNode);
     }
 
-    private boolean requiresResolution(Key key) {
-      return new LegacyRequiresResolutionChecker().requiresResolution(key);
+    private void addNode(Node node) {
+      network.addNode(node);
+      // Subcomponent creator bindings have an implicit edge to the subcomponent they create.
+      if (node instanceof BindingNode && ((BindingNode) node).kind() == SUBCOMPONENT_CREATOR) {
+        addSubcomponentEdge((BindingNode) node);
+      }
     }
 
-    private boolean requiresResolution(Binding binding) {
-      return new LegacyRequiresResolutionChecker().requiresResolution(binding);
+    private void addDependencyEdges(
+        Node parent, ResolvedBindings dependencies, DependencyRequest request) {
+      if (dependencies.isEmpty()) {
+        addDependencyEdge(parent, missingBinding(request.key()), request);
+      } else {
+        dependencies.bindingNodes()
+            .forEach(dependency -> addDependencyEdge(parent, dependency, request));
+      }
     }
 
-    private final class LegacyRequiresResolutionChecker {
-      private final Set<Object> cycleChecker = new HashSet<>();
+    private void addDependencyEdge(Node source, Node target, DependencyRequest request) {
+      boolean isEntryPoint = source instanceof ComponentNode;
+      addEdge(source, target, new DependencyEdgeImpl(request, isEntryPoint));
+    }
 
-      /**
-       * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with
-       * contributions declared within this component's modules or optional bindings with present
-       * values declared within this component's modules, or if any of its unscoped dependencies
-       * depend on such bindings.
-       *
-       * <p>We don't care about scoped dependencies because they will never depend on bindings from
-       * subcomponents.
-       *
-       * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty
-       */
-      private boolean requiresResolution(Key key) {
-        // Don't recur infinitely if there are valid cycles in the dependency graph.
-        // http://b/23032377
-        if (!cycleChecker.add(key)) {
+    private void addSubcomponentEdge(BindingNode binding) {
+      checkState(binding.kind() == SUBCOMPONENT_CREATOR);
+      Resolver owningResolver =
+          getResolverLineage().reverse().stream()
+                .filter(resolver -> resolver.componentPath.equals(binding.componentPath()))
+                .collect(onlyElement());
+      ComponentDescriptor subcomponent =
+          owningResolver.componentDescriptor.getChildComponentWithBuilderType(
+              binding.key().type().xprocessing().getTypeElement());
+      ComponentNode subcomponentNode =
+          ComponentNodeImpl.create(
+              owningResolver.componentPath.childPath(
+                  DaggerTypeElement.from(subcomponent.typeElement())),
+              subcomponent);
+      addEdge(
+          binding,
+          subcomponentNode,
+          new SubcomponentCreatorBindingEdgeImpl(binding.subcomponentDeclarations()));
+    }
+
+    private void addChildFactoryMethodEdge(Resolver subcomponentResolver) {
+      componentDescriptor
+          .getFactoryMethodForChildComponent(subcomponentResolver.componentDescriptor)
+          .ifPresent(
+              childFactoryMethod
+                  -> addEdge(
+                      componentNode,
+                      subcomponentResolver.componentNode,
+                      new ChildFactoryMethodEdgeImpl(childFactoryMethod.methodElement())));
+    }
+
+    private void addEdge(Node source, Node target, Edge edge) {
+      network.addNode(source);
+      network.addNode(target);
+      network.addEdge(source, target, edge);
+    }
+
+    private MissingBinding missingBinding(Key key) {
+      // Put all missing binding nodes in the root component. This simplifies the binding graph
+      // and produces better error messages for users since all dependents point to the same node.
+      return MissingBindingImpl.create(rootResolver().componentPath, key);
+    }
+
+    private Resolver rootResolver() {
+      return parentResolver.isPresent() ? parentResolver.get().rootResolver() : this;
+    }
+
+    private final class RequiresResolutionChecker {
+      private final Map<Node, Boolean> dependsOnMissingBindingCache = new HashMap<>();
+      private final Map<Node, Boolean> dependsOnLocalBindingsCache = new HashMap<>();
+
+      boolean requiresResolution(BindingNode binding) {
+        // If we're not allowed to float then the binding cannot be re-resolved in this component.
+        if (isNotAllowedToFloat(binding)) {
           return false;
         }
-        return reentrantComputeIfAbsent(
-            keyDependsOnLocalBindingsCache, key, this::requiresResolutionUncached);
-      }
-
-      /**
-       * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable}
-       * scope) and depends on multibindings with contributions declared within this component's
-       * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend
-       * on such local multibindings.
-       *
-       * <p>We don't care about non-reusable scoped dependencies because they will never depend on
-       * multibindings with contributions from subcomponents.
-       */
-      private boolean requiresResolution(Binding binding) {
-        if (!cycleChecker.add(binding)) {
-          return false;
-        }
-        return reentrantComputeIfAbsent(
-            bindingDependsOnLocalBindingsCache, binding, this::requiresResolutionUncached);
-      }
-
-      private boolean requiresResolutionUncached(Key key) {
-        checkArgument(
-            getPreviouslyResolvedBindings(key).isPresent(),
-            "no previously resolved bindings in %s for %s",
-            Resolver.this,
-            key);
-        ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get();
-        if (hasLocalBindings(previouslyResolvedBindings)) {
+        if (hasLocalBindings(binding)) {
           return true;
         }
-
-        for (Binding binding : previouslyResolvedBindings.bindings()) {
-          if (requiresResolution(binding)) {
-            return true;
-          }
-        }
-        return false;
+        return shouldCheckDependencies(binding)
+            // Try to re-resolving bindings that depend on missing bindings. The missing bindings
+            // will still end up being reported for cases where the binding is not allowed to float,
+            // but re-resolving allows cases that are allowed to float to be re-resolved which can
+            // prevent misleading dependency traces that include all floatable bindings.
+            // E.g. see MissingBindingSuggestionsTest#bindsMissingBinding_fails().
+            && (dependsOnLocalBinding(binding) || dependsOnMissingBinding(binding));
       }
 
-      private boolean requiresResolutionUncached(Binding binding) {
-        if ((!binding.scope().isPresent() || binding.scope().get().isReusable())
+      private boolean isNotAllowedToFloat(BindingNode binding) {
+        // In general, @Provides/@Binds/@Production bindings are allowed to float to get access to
+        // multibinding contributions that are contributed in subcomponents. However, they aren't
+        // allowed to float to get access to missing bindings that are installed in subcomponents,
+        // so we prevent floating if these bindings depend on a missing binding.
+        return binding.kind() != BindingKind.INJECTION
+            && binding.kind() != BindingKind.ASSISTED_INJECTION
+            && dependsOnMissingBinding(binding);
+      }
+
+      private boolean dependsOnMissingBinding(BindingNode binding) {
+        if (!dependsOnMissingBindingCache.containsKey(binding)) {
+          visitUncachedDependencies(binding);
+        }
+        return checkNotNull(dependsOnMissingBindingCache.get(binding));
+      }
+
+      private boolean dependsOnLocalBinding(BindingNode binding) {
+        if (!dependsOnLocalBindingsCache.containsKey(binding)) {
+          visitUncachedDependencies(binding);
+        }
+        return checkNotNull(dependsOnLocalBindingsCache.get(binding));
+      }
+
+      private void visitUncachedDependencies(BindingNode binding) {
+        // We use Tarjan's algorithm to visit the uncached dependencies of the binding grouped by
+        // strongly connected nodes (i.e. cycles) and iterated in reverse topological order.
+        for (ImmutableSet<Node> cycleNodes : stronglyConnectedNodes(binding)) {
+          // As a sanity check, verify that none of the keys in the cycle are cached yet.
+          checkState(cycleNodes.stream().noneMatch(dependsOnLocalBindingsCache::containsKey));
+          checkState(cycleNodes.stream().noneMatch(dependsOnMissingBindingCache::containsKey));
+          boolean dependsOnMissingBinding =
+              cycleNodes.stream().anyMatch(this::isMissingBinding)
+              || cycleNodes.stream()
+                  .filter(this::shouldCheckDependencies)
+                  .flatMap(this::dependencyStream)
+                  .filter(not(cycleNodes::contains))
+                  .anyMatch(dependsOnMissingBindingCache::get);
+          // All keys in the cycle have the same cached value since they all depend on each other.
+          cycleNodes.forEach(
+              cycleNode -> dependsOnMissingBindingCache.put(cycleNode, dependsOnMissingBinding));
+
+          // Note that we purposely don't filter out scoped bindings below. In particular, there are
+          // currently 3 cases where hasLocalBinding will return true:
+          //
+          //   1) The binding is MULTIBOUND_SET/MULTIBOUND_MAP and depends on an explicit
+          //      multibinding contributions in the current component.
+          //   2) The binding is OPTIONAL and depends on an explicit binding contributed in the
+          //      current component.
+          //   3) The binding has a duplicate explicit binding contributed in this component.
+          //
+          // For case #1 and #2 it's not actually required to check for scope because those are
+          // synthetic bindings which are never scoped.
+          //
+          // For case #3 we actually want don't want to rule out a scoped binding, e.g. in the case
+          // where we have a floating @Inject Foo(Bar bar) binding with @Singleton Bar provided in
+          // the ParentComponent and a duplicate Bar provided in the ChildComponent we want to
+          // reprocess Foo so that we can report the duplicate Bar binding.
+          boolean dependsOnLocalBindings =
+              // First, check if any of the bindings themselves depends on local bindings.
+              cycleNodes.stream().anyMatch(this::hasLocalBindings)
+              // Next, check if any of the dependencies (that aren't in the cycle itself) depend
+              // on local bindings. We should be guaranteed that all dependencies are cached since
+              // Tarjan's algorithm is traversed in reverse topological order.
+              || cycleNodes.stream()
+                  .filter(this::shouldCheckDependencies)
+                  .flatMap(this::dependencyStream)
+                  .filter(not(cycleNodes::contains))
+                  .anyMatch(dependsOnLocalBindingsCache::get);
+          // All keys in the cycle have the same cached value since they all depend on each other.
+          cycleNodes.forEach(
+              cycleNode -> dependsOnLocalBindingsCache.put(cycleNode, dependsOnLocalBindings));
+        }
+      }
+
+      /**
+       * Returns a list of strongly connected components in reverse topological order, starting from
+       * the given {@code rootNode} and traversing its transitive dependencies.
+       *
+       * <p>Note that the returned list may not include all transitive dependencies of the {@code
+       * rootNode} because we intentionally stop at dependencies that:
+       *
+       * <ul>
+       *   <li> Already have a cached value.
+       *   <li> Are scoped to an ancestor component (i.e. cannot depend on local bindings).
+       * </ul>
+       */
+      private ImmutableList<ImmutableSet<Node>> stronglyConnectedNodes(BindingNode rootNode) {
+        return TarjanSCCs.compute(
+            ImmutableSet.of(rootNode),
+            node -> shouldCheckDependencies(node)
+                ? dependencyStream(node)
+                    // Skip dependencies that are already cached
+                    .filter(dep -> !dependsOnLocalBindingsCache.containsKey(dep))
+                    .collect(toImmutableSet())
+                : ImmutableSet.of());
+      }
+
+      private Stream<Node> dependencyStream(Node node) {
+        return network.successors(node).stream();
+      }
+
+      private boolean shouldCheckDependencies(Node node) {
+        if (!(node instanceof BindingNode)) {
+          return false;
+        }
+        // Note: we can skip dependencies for scoped bindings because while there could be
+        // duplicates underneath the scoped binding, those duplicates are technically unused so
+        // Dagger shouldn't validate them.
+        BindingNode binding = (BindingNode) node;
+        return !isScopedToComponent(binding)
             // TODO(beder): Figure out what happens with production subcomponents.
-            && !binding.bindingType().equals(BindingType.PRODUCTION)) {
-          for (DependencyRequest dependency : binding.dependencies()) {
-            if (requiresResolution(dependency.key())) {
-              return true;
-            }
-          }
-        }
-        return false;
+            && !binding.kind().equals(BindingKind.PRODUCTION);
       }
-    }
 
-    private boolean hasLocalBindings(Binding binding) {
-      return hasLocalMultibindingContributions(binding.key())
-          || hasLocalOptionalBindingContribution(
-              binding.key(), ImmutableSet.of((ContributionBinding) binding));
-    }
+      private boolean isScopedToComponent(BindingNode binding) {
+        return binding.scope().isPresent() && !binding.scope().get().isReusable();
+      }
 
-    private boolean hasLocalBindings(ResolvedBindings resolvedBindings) {
-      return hasLocalMultibindingContributions(resolvedBindings.key())
-          || hasLocalOptionalBindingContribution(resolvedBindings);
+      private boolean isMissingBinding(Node binding) {
+        return binding instanceof MissingBinding;
+      }
+
+      private boolean hasLocalBindings(Node node) {
+        if (!(node instanceof BindingNode)) {
+          return false;
+        }
+        BindingNode binding = (BindingNode) node;
+        return hasLocalMultibindingContributions(binding)
+            || hasLocalOptionalBindingContribution(binding)
+            || hasDuplicateExplicitBinding(binding);
+      }
     }
 
     /**
-     * Returns {@code true} if there is at least one multibinding contribution declared within
-     * this component's modules that matches the key.
+     * Returns {@code true} if there's a contribution in this component matching the given binding
+     * key.
      */
-    private boolean hasLocalMultibindingContributions(Key requestKey) {
-      return keysMatchingRequest(requestKey)
-          .stream()
-          .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty());
+    private boolean hasLocalMultibindingContributions(BindingNode binding) {
+      return !declarations.multibindingContributions(binding.key()).isEmpty()
+          || !declarations.delegateMultibindingContributions(binding.key()).isEmpty();
     }
 
     /**
      * Returns {@code true} if there is a contribution in this component for an {@code
      * Optional<Foo>} key that has not been contributed in a parent.
      */
-    private boolean hasLocalOptionalBindingContribution(ResolvedBindings resolvedBindings) {
-      return hasLocalOptionalBindingContribution(
-          resolvedBindings.key(), resolvedBindings.contributionBindings());
-    }
-
-    private boolean hasLocalOptionalBindingContribution(
-          Key key, ImmutableSet<ContributionBinding> previousContributionBindings) {
-      if (previousContributionBindings.stream()
-          .map(ContributionBinding::kind)
-          .anyMatch(isEqual(OPTIONAL))) {
-        return !getLocalExplicitBindings(keyFactory.unwrapOptional(key).get())
-            .isEmpty();
+    private boolean hasLocalOptionalBindingContribution(BindingNode binding) {
+      if (binding.kind() == OPTIONAL) {
+        return hasLocalExplicitBindings(keyFactory.unwrapOptional(binding.key()).get());
       } else {
         // If a parent contributes a @Provides Optional<Foo> binding and a child has a
         // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for
         // Foo on its own
-        return !getOptionalBindingDeclarations(key).isEmpty();
+        return !getOptionalBindingDeclarations(binding.key()).isEmpty();
       }
     }
-  }
 
-  /**
-   * A multimap of those {@code declarations} that are multibinding contribution declarations,
-   * indexed by the key of the set or map to which they contribute.
-   */
-  static <T extends BindingDeclaration>
-      ImmutableSetMultimap<Key, T> multibindingContributionsByMultibindingKey(
-          Iterable<T> declarations) {
-    ImmutableSetMultimap.Builder<Key, T> builder = ImmutableSetMultimap.builder();
-    for (T declaration : declarations) {
-      if (declaration.key().multibindingContributionIdentifier().isPresent()) {
-        builder.put(declaration.key().withoutMultibindingContributionIdentifier(), declaration);
-      }
+    /**
+     * Returns {@code true} if there is at least one explicit binding that matches the given key.
+     */
+    private boolean hasLocalExplicitBindings(Key requestKey) {
+      return !declarations.bindings(requestKey).isEmpty()
+          || !declarations.delegates(requestKey).isEmpty();
     }
-    return builder.build();
+
+    /** Returns {@code true} if this resolver has a duplicate explicit binding to resolve. */
+    private boolean hasDuplicateExplicitBinding(BindingNode binding) {
+      // By default, we don't actually report an error when an explicit binding tries to override
+      // an injection binding (b/312202845). For now, ignore injection bindings unless we actually
+      // will report an error, otherwise we'd end up silently overriding the binding rather than
+      // reporting a duplicate.
+      // TODO(b/312202845): This can be removed once b/312202845 is fixed.
+      if (binding.kind() == BindingKind.INJECTION
+              && !compilerOptions.explicitBindingConflictsWithInjectValidationType()
+                  .diagnosticKind()
+                  .equals(Optional.of(Diagnostic.Kind.ERROR))) {
+        return false;
+      }
+
+      // If the current component has an explicit binding for the same key it must be a duplicate.
+      return hasLocalExplicitBindings(binding.key());
+    }
   }
 }
diff --git a/java/dagger/internal/codegen/binding/BindingGraphTransformations.java b/java/dagger/internal/codegen/binding/BindingGraphTransformations.java
new file mode 100644
index 0000000..405d6b2
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/BindingGraphTransformations.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import dagger.internal.codegen.base.TarjanSCCs;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import java.util.Map;
+
+/** Transformations on the binding graph network. */
+final class BindingGraphTransformations {
+  /** Returns a network where {@link BindingType} is present for all binding nodes. */
+  static MutableNetwork<Node, Edge> withFixedBindingTypes(MutableNetwork<Node, Edge> network) {
+    ImmutableSet<BindingNode> bindingsToFix = bindingsWithMissingBindingTypes(network);
+    if (bindingsToFix.isEmpty()) {
+      return network;
+    }
+
+    MutableNetwork<Node, Edge> fixedNetwork = withFixedBindingTypes(network, bindingsToFix);
+
+    // Check that all bindings now have a BindingType in the fixed network.
+    checkState(bindingsWithMissingBindingTypes(fixedNetwork).isEmpty());
+    return fixedNetwork;
+  }
+
+  private static MutableNetwork<Node, Edge> withFixedBindingTypes(
+      Network<Node, Edge> network, ImmutableSet<BindingNode> bindingsToFix) {
+    // Topologically sort the bindings so that we're guaranteed all dependencies of a binding are
+    // fixed before the bindings itself is fixed.
+    ImmutableList<ImmutableSet<BindingNode>> topologicallySortedBindingsToFix =
+        TarjanSCCs.compute(
+            bindingsToFix,
+            binding ->
+                network.successors(binding).stream()
+                    .flatMap(instancesOf(BindingNode.class))
+                    // Filter because we only care about direct dependencies on bindings that need
+                    // to be fixed. There might be other cycles through nodes that already have a
+                    // type, but those don't matter because it won't affect how we will fix the
+                    // types for these bindings.
+                    .filter(bindingsToFix::contains)
+                    .collect(toImmutableSet()));
+
+    Map<BindingNode, BindingNode> replacements =
+        Maps.newHashMapWithExpectedSize(bindingsToFix.size());
+    for (ImmutableSet<BindingNode> connectedBindings : topologicallySortedBindingsToFix) {
+      BindingType successorBindingType =
+          connectedBindings.stream()
+                  .flatMap(binding -> network.successors(binding).stream())
+                  .flatMap(instancesOf(BindingNode.class))
+                  .filter(binding -> !connectedBindings.contains(binding))
+                  .map(binding -> replacements.getOrDefault(binding, binding))
+                  .anyMatch(BindingNode::isProduction)
+              ? BindingType.PRODUCTION
+              : BindingType.PROVISION;
+      for (BindingNode bindingNode : connectedBindings) {
+        replacements.put(bindingNode, bindingNode.withBindingType(successorBindingType));
+      }
+    }
+    return withReplacedBindings(network, ImmutableMap.copyOf(replacements));
+  }
+
+  private static ImmutableSet<BindingNode> bindingsWithMissingBindingTypes(
+      Network<Node, Edge> network) {
+    return network.nodes().stream()
+        .flatMap(instancesOf(BindingNode.class))
+        .filter(binding -> binding.delegate().optionalBindingType().isEmpty())
+        .collect(toImmutableSet());
+  }
+
+  // Note: This method creates an entirely new network rather than replacing individual nodes and
+  // edges in the original network. We can reconsider this choice, e.g. if it turns out to be
+  // too inefficient, but my initial thought is that this approach is a bit nicer because it
+  // maintains the original node and edge iteration order, which could be nice for debugging.
+  private static MutableNetwork<Node, Edge> withReplacedBindings(
+      Network<Node, Edge> network, ImmutableMap<? extends Node, ? extends Node> replacementNodes) {
+    MutableNetwork<Node, Edge> newNetwork = NetworkBuilder.from(network).build();
+    for (Node node : network.nodes()) {
+      newNetwork.addNode(replacementNodes.containsKey(node) ? replacementNodes.get(node) : node);
+    }
+    for (Edge edge : network.edges()) {
+      EndpointPair<Node> incidentNodes = network.incidentNodes(edge);
+      Node source = incidentNodes.source();
+      Node target = incidentNodes.target();
+      newNetwork.addEdge(
+          replacementNodes.containsKey(source) ? replacementNodes.get(source) : source,
+          replacementNodes.containsKey(target) ? replacementNodes.get(target) : target,
+          edge);
+    }
+    return newNetwork;
+  }
+
+  private BindingGraphTransformations() {}
+}
diff --git a/java/dagger/internal/codegen/binding/BindingNode.java b/java/dagger/internal/codegen/binding/BindingNode.java
index 7856420..9818c39 100644
--- a/java/dagger/internal/codegen/binding/BindingNode.java
+++ b/java/dagger/internal/codegen/binding/BindingNode.java
@@ -16,14 +16,11 @@
 
 package dagger.internal.codegen.binding;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.BindingType.PRODUCTION;
 
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import dagger.BindsOptionalOf;
-import dagger.Module;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.ComponentPath;
 import dagger.internal.codegen.model.DaggerElement;
@@ -31,37 +28,19 @@
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.model.Scope;
-import dagger.multibindings.Multibinds;
 import java.util.Optional;
+import javax.inject.Inject;
 
 /**
  * An implementation of {@link dagger.internal.codegen.model.Binding} that also exposes {@link
- * BindingDeclaration}s associated with the binding.
+ * Declaration}s associated with the binding.
  */
 // TODO(dpb): Consider a supertype of dagger.internal.codegen.model.Binding that
 // dagger.internal.codegen.binding.Binding
 // could also implement.
 @AutoValue
 public abstract class BindingNode implements dagger.internal.codegen.model.Binding {
-  public static BindingNode create(
-      ComponentPath component,
-      Binding delegate,
-      ImmutableSet<MultibindingDeclaration> multibindingDeclarations,
-      ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations,
-      ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations,
-      BindingDeclarationFormatter bindingDeclarationFormatter) {
-    BindingNode node =
-        new AutoValue_BindingNode(
-            component,
-            delegate,
-            multibindingDeclarations,
-            optionalBindingDeclarations,
-            subcomponentDeclarations);
-    node.bindingDeclarationFormatter = checkNotNull(bindingDeclarationFormatter);
-    return node;
-  }
-
-  private BindingDeclarationFormatter bindingDeclarationFormatter;
+  private DeclarationFormatter declarationFormatter;
 
   public abstract Binding delegate();
 
@@ -81,7 +60,7 @@
    *   <li>{@linkplain Multibinds multibinding} declarations
    * </ul>
    */
-  public final Iterable<BindingDeclaration> associatedDeclarations() {
+  public final Iterable<Declaration> associatedDeclarations() {
     return Iterables.concat(
         multibindingDeclarations(), optionalBindingDeclarations(), subcomponentDeclarations());
   }
@@ -133,6 +112,77 @@
 
   @Override
   public final String toString() {
-    return bindingDeclarationFormatter.format(delegate());
+    return declarationFormatter.format(delegate());
+  }
+
+  public BindingNode withBindingType(BindingType bindingType) {
+    return create(
+        componentPath(),
+        ((ContributionBinding) delegate()).withBindingType(bindingType),
+        multibindingDeclarations(),
+        optionalBindingDeclarations(),
+        subcomponentDeclarations(),
+        declarationFormatter);
+  }
+
+  static final class Factory {
+    private final DeclarationFormatter declarationFormatter;
+
+    @Inject
+    Factory(DeclarationFormatter declarationFormatter) {
+      this.declarationFormatter = declarationFormatter;
+    }
+
+    public BindingNode forContributionBindings(
+        ComponentPath component,
+        ContributionBinding delegate,
+        Iterable<MultibindingDeclaration> multibindingDeclarations,
+        Iterable<OptionalBindingDeclaration> optionalBindingDeclarations,
+        Iterable<SubcomponentDeclaration> subcomponentDeclarations) {
+      return create(
+          component,
+          delegate,
+          ImmutableSet.copyOf(multibindingDeclarations),
+          ImmutableSet.copyOf(optionalBindingDeclarations),
+          ImmutableSet.copyOf(subcomponentDeclarations));
+    }
+
+    public BindingNode forMembersInjectionBinding(
+        ComponentPath component, MembersInjectionBinding delegate) {
+      return create(component, delegate, ImmutableSet.of(), ImmutableSet.of(), ImmutableSet.of());
+    }
+
+    private BindingNode create(
+        ComponentPath component,
+        Binding delegate,
+        ImmutableSet<MultibindingDeclaration> multibindingDeclarations,
+        ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations,
+        ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
+      return BindingNode.create(
+          component,
+          delegate,
+          multibindingDeclarations,
+          optionalBindingDeclarations,
+          subcomponentDeclarations,
+          declarationFormatter);
+    }
+  }
+
+  private static BindingNode create(
+      ComponentPath component,
+      Binding delegate,
+      ImmutableSet<MultibindingDeclaration> multibindingDeclarations,
+      ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations,
+      ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations,
+      DeclarationFormatter declarationFormatter) {
+    BindingNode node =
+        new AutoValue_BindingNode(
+            component,
+            delegate,
+            multibindingDeclarations,
+            optionalBindingDeclarations,
+            subcomponentDeclarations);
+    node.declarationFormatter = declarationFormatter;
+    return node;
   }
 }
diff --git a/java/dagger/internal/codegen/binding/BoundInstanceBinding.java b/java/dagger/internal/codegen/binding/BoundInstanceBinding.java
new file mode 100644
index 0000000..e974de2
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/BoundInstanceBinding.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#BOUND_INSTANCE}. */
+@CheckReturnValue
+@AutoValue
+public abstract class BoundInstanceBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.BOUND_INSTANCE;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public final ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_BoundInstanceBinding.Builder();
+  }
+
+  /** A {@link BoundInstanceBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<BoundInstanceBinding, Builder> {
+    abstract Builder nullability(Nullability nullability);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentBinding.java b/java/dagger/internal/codegen/binding/ComponentBinding.java
new file mode 100644
index 0000000..a5eda78
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/ComponentBinding.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#COMPONENT}. */
+@CheckReturnValue
+@AutoValue
+public abstract class ComponentBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.COMPONENT;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public final ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_ComponentBinding.Builder();
+  }
+
+  /** A {@link ComponentBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder extends ContributionBinding.Builder<ComponentBinding, Builder> {}
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
index 254ca7e..cf978a2 100644
--- a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
@@ -41,6 +41,7 @@
 import dagger.internal.codegen.base.ComponentCreatorKind;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
 import dagger.internal.codegen.xprocessing.XElements;
 import java.util.List;
 
@@ -217,7 +218,10 @@
       DependencyRequest request =
           dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType);
       return ComponentRequirement.forBoundInstance(
-          request.key(), request.isNullable(), elementForVariableName);
+          request.key(),
+          request.isNullable(),
+          elementForVariableName,
+          Nullability.of(elementForVariableName));
     }
 
     return parameterType.getTypeElement().hasAnyAnnotation(moduleAnnotations())
diff --git a/java/dagger/internal/codegen/binding/ComponentDeclarations.java b/java/dagger/internal/codegen/binding/ComponentDeclarations.java
new file mode 100644
index 0000000..2855722
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/ComponentDeclarations.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimaps;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.WildcardTypeName;
+import dagger.internal.codegen.base.DaggerSuperficialValidation;
+import dagger.internal.codegen.base.FrameworkTypes;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Key.MultibindingContributionIdentifier;
+import java.util.Optional;
+import javax.inject.Inject;
+
+/** Stores the bindings and declarations of a component by key. */
+final class ComponentDeclarations {
+  private final KeyFactory keyFactory;
+  private final ImmutableSetMultimap<Key, ContributionBinding> bindings;
+  private final ImmutableSetMultimap<Key, DelegateDeclaration> delegates;
+  private final ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindings;
+  private final ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponents;
+  private final ImmutableSetMultimap<TypeNameKey, MultibindingDeclaration> multibindings;
+  private final ImmutableSetMultimap<TypeNameKey, ContributionBinding> multibindingContributions;
+  private final ImmutableSetMultimap<TypeNameKey, DelegateDeclaration>
+      delegateMultibindingContributions;
+
+  private ComponentDeclarations(
+      KeyFactory keyFactory,
+      ImmutableSetMultimap<Key, ContributionBinding> bindings,
+      ImmutableSetMultimap<Key, DelegateDeclaration> delegates,
+      ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindings,
+      ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponents,
+      ImmutableSetMultimap<TypeNameKey, MultibindingDeclaration> multibindings,
+      ImmutableSetMultimap<TypeNameKey, ContributionBinding> multibindingContributions,
+      ImmutableSetMultimap<TypeNameKey, DelegateDeclaration> delegateMultibindingContributions) {
+    this.keyFactory = keyFactory;
+    this.bindings = bindings;
+    this.delegates = delegates;
+    this.optionalBindings = optionalBindings;
+    this.subcomponents = subcomponents;
+    this.multibindings = multibindings;
+    this.multibindingContributions = multibindingContributions;
+    this.delegateMultibindingContributions = delegateMultibindingContributions;
+  }
+
+  ImmutableSet<ContributionBinding> bindings(Key key) {
+    return bindings.get(key);
+  }
+
+  ImmutableSet<DelegateDeclaration> delegates(Key key) {
+    // @Binds @IntoMap declarations have key Map<K, V> but may be requested as
+    // Map<K, Provider/Producer<V>> keys, so unwrap the multibinding map contribution key first.
+    // TODO(b/366277730): This can be simplified to "delegates.get(key)" once the flag for
+    // "useFrameworkTypeInMapMultibindingContributionKey" is removed.
+    return delegates.get(
+        key.multibindingContributionIdentifier().isPresent()
+            // TODO(bcorso): Consider using TypeNameKey here instead of Key, to avoid losing
+            // variance information when unwrapping KSP types (see TypeNameKey's javadoc).
+            ? keyFactory.unwrapMapValueType(key)
+            : key);
+  }
+
+  /**
+   * Returns the delegate multibinding contributions (e.g. {@code @Binds @IntoMap}) for the given
+   * {@code key}, or an empty set if none exist.
+   *
+   * <p>For map multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Map<K, V>}
+   *   <li> {@code Map<K, Provider<V>>}
+   *   <li> {@code Map<K, Producer<V>>}
+   *   <li> {@code Map<K, Produced<V>>}
+   * </ul>
+   *
+   * <p>For set multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Set<V>}
+   *   <li> {@code Set<Produced<V>>}
+   * </ul>
+   */
+  ImmutableSet<DelegateDeclaration> delegateMultibindingContributions(Key key) {
+    return delegateMultibindingContributions.get(unwrapMultibindingKey(key));
+  }
+
+  /**
+   * Returns the multibinding declarations (i.e. {@code @Multibinds}) for the given {@code key}, or
+   * an empty set if none exists.
+   *
+   * <p>For map multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Map<K, V>}
+   *   <li> {@code Map<K, Provider<V>>}
+   *   <li> {@code Map<K, Producer<V>>}
+   *   <li> {@code Map<K, Produced<V>>}
+   * </ul>
+   *
+   * <p>For set multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Set<V>}
+   *   <li> {@code Set<Produced<V>>}
+   * </ul>
+   */
+  ImmutableSet<MultibindingDeclaration> multibindings(Key key) {
+    return multibindings.get(unwrapMultibindingKey(key));
+  }
+
+  /**
+   * Returns the multibinding contributions (e.g. {@code @Provides @IntoMap}) for the given
+   * {@code key}, or an empty set if none exists.
+   *
+   * <p>For map multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Map<K, V>}
+   *   <li> {@code Map<K, Provider<V>>}
+   *   <li> {@code Map<K, Producer<V>>}
+   *   <li> {@code Map<K, Produced<V>>}
+   * </ul>
+   *
+   * <p>For set multibindings, the following request keys represent the same underlying binding and
+   * will return the same results:
+   * <ul>
+   *   <li> {@code Set<V>}
+   *   <li> {@code Set<Produced<V>>}
+   * </ul>
+   */
+  ImmutableSet<ContributionBinding> multibindingContributions(Key key) {
+    return multibindingContributions.get(unwrapMultibindingKey(key));
+  }
+
+  ImmutableSet<OptionalBindingDeclaration> optionalBindings(Key key) {
+    return optionalBindings.get(key);
+  }
+
+  ImmutableSet<SubcomponentDeclaration> subcomponents(Key key) {
+    return subcomponents.get(key);
+  }
+
+  ImmutableSet<Declaration> allDeclarations() {
+    return ImmutableSet.<Declaration>builder()
+        .addAll(bindings.values())
+        .addAll(delegates.values())
+        .addAll(multibindings.values())
+        .addAll(optionalBindings.values())
+        .addAll(subcomponents.values())
+        .build();
+  }
+
+  static final class Factory {
+    private final XProcessingEnv processingEnv;
+    private final KeyFactory keyFactory;
+    private final ModuleDescriptor.Factory moduleDescriptorFactory;
+
+    @Inject
+    Factory(
+        XProcessingEnv processingEnv,
+        KeyFactory keyFactory,
+        ModuleDescriptor.Factory moduleDescriptorFactory) {
+      this.processingEnv = processingEnv;
+      this.keyFactory = keyFactory;
+      this.moduleDescriptorFactory = moduleDescriptorFactory;
+    }
+
+    ComponentDeclarations create(
+        Optional<ComponentDescriptor> parentDescriptor, ComponentDescriptor descriptor) {
+      ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
+      ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder();
+      ImmutableSet.Builder<MultibindingDeclaration> multibindings = ImmutableSet.builder();
+      ImmutableSet.Builder<OptionalBindingDeclaration> optionalBindings =ImmutableSet.builder();
+      ImmutableSet.Builder<SubcomponentDeclaration> subcomponents = ImmutableSet.builder();
+
+      bindings.addAll(descriptor.bindings());
+      delegates.addAll(descriptor.delegateDeclarations());
+      multibindings.addAll(descriptor.multibindingDeclarations());
+      optionalBindings.addAll(descriptor.optionalBindingDeclarations());
+      subcomponents.addAll(descriptor.subcomponentDeclarations());
+
+      // Note: The implicit production modules are not included directly in the component descriptor
+      // because we don't know whether to install them or not without knowing the parent component.
+      for (ModuleDescriptor module : implicitProductionModules(descriptor, parentDescriptor)) {
+        bindings.addAll(module.bindings());
+        delegates.addAll(module.delegateDeclarations());
+        multibindings.addAll(module.multibindingDeclarations());
+        optionalBindings.addAll(module.optionalDeclarations());
+        subcomponents.addAll(module.subcomponentDeclarations());
+      }
+
+      return new ComponentDeclarations(
+          keyFactory,
+          indexDeclarationsByKey(bindings.build()),
+          indexDeclarationsByKey(delegates.build()),
+          indexDeclarationsByKey(optionalBindings.build()),
+          indexDeclarationsByKey(subcomponents.build()),
+          // The @Multibinds declarations and @IntoSet/@IntoMap multibinding contributions are all
+          // indexed by their "unwrapped" multibinding key (i.e. Map<K, V> or Set<V>) so that we
+          // don't have to check multiple different keys to gather all of the contributions.
+          indexDeclarationsByUnwrappedMultibindingKey(multibindings.build()),
+          indexDeclarationsByUnwrappedMultibindingKey(multibindingContributions(bindings.build())),
+          indexDeclarationsByUnwrappedMultibindingKey(
+              multibindingContributions(delegates.build())));
+    }
+
+    /**
+     * Returns all the modules that should be installed in the component. For production components
+     * and production subcomponents that have a parent that is not a production component or
+     * subcomponent, also includes the production monitoring module for the component and the
+     * production executor module.
+     */
+    private ImmutableSet<ModuleDescriptor> implicitProductionModules(
+        ComponentDescriptor descriptor, Optional<ComponentDescriptor> parentDescriptor) {
+      return shouldIncludeImplicitProductionModules(descriptor, parentDescriptor)
+          ? ImmutableSet.of(
+              moduleDescriptorFactory.create(
+                  DaggerSuperficialValidation.requireTypeElement(
+                      processingEnv,
+                      toJavaPoet(generatedMonitoringModuleName(descriptor.typeElement())))),
+              moduleDescriptorFactory.create(
+                  processingEnv.requireTypeElement(TypeNames.PRODUCTION_EXECTUTOR_MODULE)))
+          : ImmutableSet.of();
+    }
+
+    private static boolean shouldIncludeImplicitProductionModules(
+        ComponentDescriptor descriptor, Optional<ComponentDescriptor> parentDescriptor) {
+      return descriptor.isProduction()
+          && descriptor.isRealComponent()
+          && (parentDescriptor.isEmpty() || !parentDescriptor.get().isProduction());
+    }
+
+    /** Indexes {@code bindingDeclarations} by {@link Declaration#key()}. */
+    private static <T extends Declaration>
+        ImmutableSetMultimap<Key, T> indexDeclarationsByKey(Iterable<T> declarations) {
+      return ImmutableSetMultimap.copyOf(Multimaps.index(declarations, Declaration::key));
+    }
+
+    /** Indexes {@code bindingDeclarations} by the unwrapped multibinding key. */
+    private <T extends Declaration> ImmutableSetMultimap<TypeNameKey, T>
+        indexDeclarationsByUnwrappedMultibindingKey(Iterable<T> declarations) {
+      return ImmutableSetMultimap.copyOf(
+          Multimaps.index(
+              declarations,
+              declaration ->
+                  unwrapMultibindingKey(
+                      declaration.key().withoutMultibindingContributionIdentifier())));
+    }
+
+    private static <T extends Declaration> ImmutableSet<T> multibindingContributions(
+        ImmutableSet<T> declarations) {
+      return declarations.stream()
+          .filter(declaration -> declaration.key().multibindingContributionIdentifier().isPresent())
+          .collect(toImmutableSet());
+    }
+  }
+
+  /**
+   * Returns a {@link TypeNameKey} with the same qualifiers and multibinding identifier as the
+   * original key, but with an unwrapped typed.
+   *
+   * <p>In this case, an unwrapped type is a map or set where the value type has been stripped of a
+   * leading framework type. If the given type is neither a map nor set type, then the original type
+   * is returned.
+   *
+   * <p>The following map types have an unwrapped type equal to {@code Map<K, V>}:
+   * <ul>
+   *   <li> {@code Map<K, V>}
+   *   <li> {@code Map<K, Provider<V>>}
+   *   <li> {@code Map<K, Producer<V>>}
+   *   <li> {@code Map<K, Produced<V>>}
+   * </ul>
+   *
+   * <p>The following set types have an unwrapped type equal to {@code Set<V>}:
+   * <ul>
+   *   <li> {@code Set<V>}
+   *   <li> {@code Set<Produced<V>>}
+   * </ul>
+   */
+  private static TypeNameKey unwrapMultibindingKey(Key multibindingKey) {
+    return TypeNameKey.from(
+        multibindingKey.multibindingContributionIdentifier(),
+        multibindingKey.qualifier(),
+        unwrapMultibindingTypeName(multibindingKey.type().xprocessing().getTypeName()));
+  }
+
+  private static TypeName unwrapMultibindingTypeName(TypeName typeName) {
+    if (isValidMapMultibindingTypeName(typeName)) {
+      ParameterizedTypeName mapTypeName = (ParameterizedTypeName) typeName;
+      TypeName mapKeyTypeName = mapTypeName.typeArguments.get(0);
+      TypeName mapValueTypeName = mapTypeName.typeArguments.get(1);
+      return ParameterizedTypeName.get(
+            mapTypeName.rawType,
+            mapKeyTypeName,
+            unwrapFrameworkTypeName(mapValueTypeName, FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES));
+    }
+    if (isValidSetMultibindingTypeName(typeName)) {
+      ParameterizedTypeName setTypeName = (ParameterizedTypeName) typeName;
+      TypeName setValueTypeName = getOnlyElement(setTypeName.typeArguments);
+      return ParameterizedTypeName.get(
+          setTypeName.rawType,
+          unwrapFrameworkTypeName(setValueTypeName, FrameworkTypes.SET_VALUE_FRAMEWORK_TYPES));
+    }
+    return typeName;
+  }
+
+  private static boolean isValidMapMultibindingTypeName(TypeName typeName) {
+    if (!(typeName instanceof ParameterizedTypeName)) {
+      return false;
+    }
+    ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
+    return parameterizedTypeName.rawType.equals(TypeNames.MAP)
+        && parameterizedTypeName.typeArguments.size() == 2
+        && !(parameterizedTypeName.typeArguments.get(0) instanceof WildcardTypeName)
+        && !(parameterizedTypeName.typeArguments.get(1) instanceof WildcardTypeName);
+  }
+
+  private static boolean isValidSetMultibindingTypeName(TypeName typeName) {
+    if (!(typeName instanceof ParameterizedTypeName)) {
+      return false;
+    }
+    ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
+    return parameterizedTypeName.rawType.equals(TypeNames.SET)
+        && parameterizedTypeName.typeArguments.size() == 1
+        && !(getOnlyElement(parameterizedTypeName.typeArguments) instanceof WildcardTypeName);
+  }
+
+  private static TypeName unwrapFrameworkTypeName(
+      TypeName typeName, ImmutableSet<ClassName> frameworkTypeNames) {
+    if (typeName instanceof ParameterizedTypeName) {
+      ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
+      if (frameworkTypeNames.contains(parameterizedTypeName.rawType)) {
+        typeName = getOnlyElement(parameterizedTypeName.typeArguments);
+      }
+    }
+    return typeName;
+  }
+
+  /**
+   * Represents a class similar to {@link Key} but uses {@link TypeName} rather than {@code XType}.
+   *
+   * <p>We use {@code TypeName} rather than {@code XType} here because we can lose variance
+   * information when unwrapping an {@code XType} in KSP (b/352142595), and using {@code TypeName}
+   * avoids this issue.
+   */
+  @AutoValue
+  abstract static class TypeNameKey {
+    static TypeNameKey from(
+        Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier,
+        Optional<DaggerAnnotation> qualifier,
+        TypeName typeName) {
+      return new AutoValue_ComponentDeclarations_TypeNameKey(
+          multibindingContributionIdentifier, qualifier, typeName);
+    }
+
+    abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
+
+    abstract Optional<DaggerAnnotation> qualifier();
+
+    abstract TypeName type();
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java
new file mode 100644
index 0000000..9b52a2c
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#COMPONENT_DEPENDENCY}. */
+@CheckReturnValue
+@AutoValue
+public abstract class ComponentDependencyBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.COMPONENT_DEPENDENCY;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_ComponentDependencyBinding.Builder();
+  }
+
+  /** A {@link ComponentDependencyBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<ComponentDependencyBinding, Builder> {}
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java
new file mode 100644
index 0000000..c646acc
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#COMPONENT_PRODUCTION}. */
+@CheckReturnValue
+@AutoValue
+public abstract class ComponentDependencyProductionBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.COMPONENT_PRODUCTION;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PRODUCTION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_ComponentDependencyProductionBinding.Builder();
+  }
+
+  /** A {@link ComponentDependencyProductionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<ComponentDependencyProductionBinding, Builder> {}
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java
new file mode 100644
index 0000000..5ae15e1
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#COMPONENT_PROVISION}. */
+@CheckReturnValue
+@AutoValue
+public abstract class ComponentDependencyProvisionBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.COMPONENT_PROVISION;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_ComponentDependencyProvisionBinding.Builder();
+  }
+
+  /** A {@link ComponentDependencyProvisionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<ComponentDependencyProvisionBinding, Builder> {
+    abstract Builder nullability(Nullability nullability);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
index b0a0183..fc2b674 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
@@ -48,6 +48,7 @@
 import com.google.auto.value.extension.memoized.Memoized;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -87,6 +88,8 @@
 @CheckReturnValue
 @AutoValue
 public abstract class ComponentDescriptor {
+  private BindingFactory bindingFactory;
+
   /** The annotation that specifies that {@link #typeElement()} is a component. */
   public abstract ComponentAnnotation annotation();
 
@@ -273,20 +276,6 @@
         builderType.getQualifiedName());
   }
 
-  /** Returns the first component method associated with this binding request, if one exists. */
-  public Optional<ComponentMethodDescriptor> firstMatchingComponentMethod(BindingRequest request) {
-    return Optional.ofNullable(firstMatchingComponentMethods().get(request));
-  }
-
-  @Memoized
-  ImmutableMap<BindingRequest, ComponentMethodDescriptor> firstMatchingComponentMethods() {
-    Map<BindingRequest, ComponentMethodDescriptor> methods = new HashMap<>();
-    for (ComponentMethodDescriptor method : entryPointMethods()) {
-      methods.putIfAbsent(BindingRequest.bindingRequest(method.dependencyRequest().get()), method);
-    }
-    return ImmutableMap.copyOf(methods);
-  }
-
   /** The entry point methods on the component type. Each has a {@link DependencyRequest}. */
   public final ImmutableSet<ComponentMethodDescriptor> entryPointMethods() {
     return componentMethods().stream()
@@ -315,6 +304,130 @@
         : Optional.empty();
   }
 
+  /** Returns the bindings for the component. */
+  @Memoized
+  public ImmutableSet<ContributionBinding> bindings() {
+    ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
+    componentBinding().ifPresent(builder::add);
+    return builder
+        .addAll(componentDependencyBindings())
+        .addAll(boundInstanceBindings())
+        .addAll(subcomponentCreatorBindings())
+        .addAll(moduleBindings())
+        .build();
+  }
+
+  /** Returns the binding for the component, itself, if this is a real component. */
+  @Memoized
+  Optional<ContributionBinding> componentBinding() {
+    return isRealComponent()
+        ? Optional.of(bindingFactory.componentBinding(typeElement()))
+        : Optional.empty();
+  }
+
+  /** Returns the bindings for the component dependency and those contributed by its methods. */
+  @Memoized
+  ImmutableSet<ContributionBinding> componentDependencyBindings() {
+    ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
+    for (ComponentRequirement dependency : dependencies()) {
+      builder.add(bindingFactory.componentDependencyBinding(dependency));
+
+      // Within a component dependency, we want to allow the same method to appear multiple
+      // times assuming it is the exact same method. We do this by tracking a set of bindings
+      // we've already added with the binding element removed since that is the only thing
+      // allowed to differ.
+      HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create();
+      XTypeElements.getAllMethods(dependency.typeElement()).stream()
+          // MembersInjection methods aren't "provided" explicitly, so ignore them.
+          .filter(ComponentDescriptor::isComponentContributionMethod)
+          .forEach(
+              method -> {
+                ContributionBinding binding =
+                    isProduction() && isComponentProductionMethod(method)
+                        ? bindingFactory.componentDependencyProductionMethodBinding(method)
+                        : bindingFactory.componentDependencyProvisionMethodBinding(method);
+                if (dedupeBindings.put(
+                    getSimpleName(method),
+                    // Remove the binding element since we know that will be different, but
+                    // everything else we want to be the same to consider it a duplicate.
+                    binding.toBuilder().clearBindingElement().build())) {
+                  builder.add(binding);
+                }
+              });
+    }
+    return builder.build();
+  }
+
+  /** Returns the {@code @BindsInstance} bindings required to create this component. */
+  @Memoized
+  ImmutableSet<ContributionBinding> boundInstanceBindings() {
+    return creatorDescriptor().isPresent()
+        ? creatorDescriptor().get().boundInstanceRequirements().stream()
+            .map(
+                requirement ->
+                    bindingFactory.boundInstanceBinding(
+                        requirement,
+                        creatorDescriptor().get().elementForRequirement(requirement)))
+            .collect(toImmutableSet())
+        : ImmutableSet.of();
+  }
+
+  /** Returns the subcomponent creator bindings for this component. */
+  @Memoized
+  ImmutableSet<ContributionBinding> subcomponentCreatorBindings() {
+    ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
+    childComponentsDeclaredByBuilderEntryPoints()
+        .forEach(
+            (builderEntryPoint, childComponent) -> {
+              if (!childComponentsDeclaredByModules().contains(childComponent)) {
+                builder.add(
+                    bindingFactory.subcomponentCreatorBinding(
+                        builderEntryPoint.methodElement(), typeElement()));
+              }
+            });
+    return builder.build();
+  }
+
+  @Memoized
+  ImmutableSet<ContributionBinding> moduleBindings() {
+    return modules().stream()
+        .map(ModuleDescriptor::bindings)
+        .flatMap(ImmutableSet::stream)
+        .collect(toImmutableSet());
+  }
+
+  @Memoized
+  public ImmutableSet<DelegateDeclaration> delegateDeclarations() {
+    return modules().stream()
+        .map(ModuleDescriptor::delegateDeclarations)
+        .flatMap(ImmutableSet::stream)
+        .collect(toImmutableSet());
+  }
+
+  @Memoized
+  public ImmutableSet<MultibindingDeclaration> multibindingDeclarations() {
+    return modules().stream()
+        .map(ModuleDescriptor::multibindingDeclarations)
+        .flatMap(ImmutableSet::stream)
+        .collect(toImmutableSet());
+  }
+
+  @Memoized
+  public ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations() {
+    return modules().stream()
+        .map(ModuleDescriptor::optionalDeclarations)
+        .flatMap(ImmutableSet::stream)
+        .collect(toImmutableSet());
+  }
+
+  @Memoized
+  public ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations() {
+    return modules().stream()
+        .map(ModuleDescriptor::subcomponentDeclarations)
+        .flatMap(ImmutableSet::stream)
+        .collect(toImmutableSet());
+  }
+
   @Memoized
   @Override
   public int hashCode() {
@@ -378,7 +491,7 @@
    * Returns {@code true} if a method could be a component entry point but not a members-injection
    * method.
    */
-  static boolean isComponentContributionMethod(XMethodElement method) {
+  private static boolean isComponentContributionMethod(XMethodElement method) {
     return method.getParameters().isEmpty()
         && !isVoid(method.getReturnType())
         && !method.getEnclosingElement().getClassName().equals(TypeName.OBJECT)
@@ -386,7 +499,7 @@
   }
 
   /** Returns {@code true} if a method could be a component production entry point. */
-  static boolean isComponentProductionMethod(XMethodElement method) {
+  private static boolean isComponentProductionMethod(XMethodElement method) {
     return isComponentContributionMethod(method) && isFutureType(method.getReturnType());
   }
 
@@ -394,6 +507,7 @@
   @Singleton
   public static final class Factory implements ClearableCache {
     private final XProcessingEnv processingEnv;
+    private final BindingFactory bindingFactory;
     private final DependencyRequestFactory dependencyRequestFactory;
     private final ModuleDescriptor.Factory moduleDescriptorFactory;
     private final InjectionAnnotations injectionAnnotations;
@@ -403,11 +517,13 @@
     @Inject
     Factory(
         XProcessingEnv processingEnv,
+        BindingFactory bindingFactory,
         DependencyRequestFactory dependencyRequestFactory,
         ModuleDescriptor.Factory moduleDescriptorFactory,
         InjectionAnnotations injectionAnnotations,
         DaggerSuperficialValidation superficialValidation) {
       this.processingEnv = processingEnv;
+      this.bindingFactory = bindingFactory;
       this.dependencyRequestFactory = dependencyRequestFactory;
       this.moduleDescriptorFactory = moduleDescriptorFactory;
       this.injectionAnnotations = injectionAnnotations;
@@ -514,17 +630,20 @@
             .map(this::subcomponentDescriptor)
             .collect(toImmutableSet());
 
-      return new AutoValue_ComponentDescriptor(
-          componentAnnotation,
-          typeElement,
-          componentDependencies,
-          transitiveModules,
-          scopes,
-          subcomponentsFromModules,
-          subcomponentsByFactoryMethod.buildOrThrow(),
-          subcomponentsByBuilderMethod.buildOrThrow(),
-          componentMethodsBuilder.build(),
-          creatorDescriptor);
+      ComponentDescriptor componentDescriptor =
+          new AutoValue_ComponentDescriptor(
+              componentAnnotation,
+              typeElement,
+              componentDependencies,
+              transitiveModules,
+              scopes,
+              subcomponentsFromModules,
+              subcomponentsByFactoryMethod.buildOrThrow(),
+              subcomponentsByBuilderMethod.buildOrThrow(),
+              componentMethodsBuilder.build(),
+              creatorDescriptor);
+      componentDescriptor.bindingFactory = bindingFactory;
+      return componentDescriptor;
     }
 
     private ComponentMethodDescriptor getDescriptorForComponentMethod(
diff --git a/java/dagger/internal/codegen/binding/ComponentRequirement.java b/java/dagger/internal/codegen/binding/ComponentRequirement.java
index 1779ec1..5813506 100644
--- a/java/dagger/internal/codegen/binding/ComponentRequirement.java
+++ b/java/dagger/internal/codegen/binding/ComponentRequirement.java
@@ -34,6 +34,7 @@
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.xprocessing.Nullability;
 import dagger.internal.codegen.xprocessing.XTypeElements;
 import java.util.Optional;
 
@@ -106,6 +107,16 @@
    */
   abstract Optional<NullPolicy> overrideNullPolicy();
 
+  /**
+   * The nullability of the requirement. If set, this is used to determine the nullability of the
+   * requirement's type.
+   */
+  public Nullability getNullability() {
+    return nullability;
+  }
+
+  private Nullability nullability = Nullability.NOT_NULLABLE;
+
   /** The requirement's null policy. */
   public NullPolicy nullPolicy() {
     if (overrideNullPolicy().isPresent()) {
@@ -179,6 +190,10 @@
     return ParameterSpec.builder(type().getTypeName(), variableName()).build();
   }
 
+  public static ComponentRequirement forDependency(ComponentDependencyBinding binding) {
+    return forDependency(binding.key().type().xprocessing());
+  }
+
   public static ComponentRequirement forDependency(XType type) {
     checkArgument(isDeclared(checkNotNull(type)));
     return create(Kind.DEPENDENCY, type);
@@ -189,18 +204,20 @@
     return create(Kind.MODULE, type);
   }
 
-  public static ComponentRequirement forBoundInstance(ContributionBinding binding) {
+  public static ComponentRequirement forBoundInstance(BoundInstanceBinding binding) {
     checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
-    return forBoundInstance(binding.key(), binding.isNullable(), binding.bindingElement().get());
+    return forBoundInstance(
+        binding.key(), binding.isNullable(), binding.bindingElement().get(), binding.nullability());
   }
 
   static ComponentRequirement forBoundInstance(
-      Key key, boolean nullable, XElement elementForVariableName) {
+      Key key, boolean nullable, XElement elementForVariableName, Nullability nullability) {
     return create(
         Kind.BOUND_INSTANCE,
         key.type().xprocessing(),
         nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(),
         Optional.of(key),
+        nullability,
         getSimpleName(elementForVariableName));
   }
 
@@ -208,9 +225,10 @@
     return create(
         kind,
         type,
-        Optional.empty(),
-        Optional.empty(),
-        simpleVariableName(type.getTypeElement().getClassName()));
+        /* overrideNullPolicy= */ Optional.empty(),
+        /* key= */ Optional.empty(),
+        Nullability.NOT_NULLABLE,
+        simpleVariableName(type.getTypeElement().asClassName()));
   }
 
   private static ComponentRequirement create(
@@ -218,10 +236,12 @@
       XType type,
       Optional<NullPolicy> overrideNullPolicy,
       Optional<Key> key,
+      Nullability nullability,
       String variableName) {
     ComponentRequirement requirement =
         new AutoValue_ComponentRequirement(
             kind, type.getTypeName(), overrideNullPolicy, key, variableName);
+    requirement.nullability = nullability;
     requirement.type = type;
     return requirement;
   }
diff --git a/java/dagger/internal/codegen/binding/ContributionBinding.java b/java/dagger/internal/codegen/binding/ContributionBinding.java
index f8950a3..9cfc722 100644
--- a/java/dagger/internal/codegen/binding/ContributionBinding.java
+++ b/java/dagger/internal/codegen/binding/ContributionBinding.java
@@ -16,23 +16,27 @@
 
 package dagger.internal.codegen.binding;
 
+import static com.google.common.base.Preconditions.checkState;
 import static dagger.internal.codegen.xprocessing.XElements.asMethod;
-import static java.util.Arrays.asList;
+import static dagger.internal.codegen.xprocessing.XElements.isAbstract;
+import static dagger.internal.codegen.xprocessing.XElements.isStatic;
 
+import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XElementKt;
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
 import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.codegen.base.ContributionType;
 import dagger.internal.codegen.base.ContributionType.HasContributionType;
 import dagger.internal.codegen.base.MapType;
 import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.model.BindingKind;
-import dagger.internal.codegen.model.DaggerAnnotation;
-import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
+import dagger.internal.codegen.xprocessing.Nullability;
 import dagger.internal.codegen.xprocessing.XTypes;
 import java.util.Optional;
 
@@ -46,8 +50,20 @@
   /** Returns the nullability of this binding. */
   public abstract Nullability nullability();
 
-  // Note: We're using DaggerAnnotation instead of XAnnotation for its equals/hashcode
-  public abstract Optional<DaggerAnnotation> mapKey();
+  private static final ImmutableSet<BindingKind> KINDS_TO_CHECK_FOR_NULL =
+      ImmutableSet.of(BindingKind.PROVISION, BindingKind.COMPONENT_PROVISION);
+
+  public boolean shouldCheckForNull(CompilerOptions compilerOptions) {
+    return KINDS_TO_CHECK_FOR_NULL.contains(kind())
+        && contributedPrimitiveType().isEmpty()
+        && !isNullable()
+        && compilerOptions.doCheckForNulls();
+  }
+
+  /** Returns the map key if this is a {@code Map} multibinding contribution. */
+  public Optional<XAnnotation> mapKey() {
+    return bindingElement().flatMap(MapKeys::getMapKey);
+  }
 
   /** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */
   public final Optional<XType> contributedPrimitiveType() {
@@ -59,7 +75,11 @@
 
   @Override
   public boolean requiresModuleInstance() {
-    return !isContributingModuleKotlinObject() && super.requiresModuleInstance();
+    return contributingModule().isPresent()
+        && bindingElement().isPresent()
+        && !isAbstract(bindingElement().get())
+        && !isStatic(bindingElement().get())
+        && !isContributingModuleKotlinObject();
   }
 
   @Override
@@ -97,33 +117,47 @@
 
   public abstract Builder<?, ?> toBuilder();
 
+  /** Returns a new {@link ContributionBinding} with the given {@link BindingType}. */
+  final ContributionBinding withBindingType(BindingType bindingType) {
+    checkState(optionalBindingType().isEmpty());
+    switch (kind()) {
+      case DELEGATE:
+        return ((DelegateBinding) this).toBuilder()
+            .optionalBindingType(Optional.of(bindingType))
+            .build();
+      case OPTIONAL:
+        return ((OptionalBinding) this).toBuilder()
+            .optionalBindingType(Optional.of(bindingType))
+            .build();
+      case MULTIBOUND_MAP:
+        return ((MultiboundMapBinding) this).toBuilder()
+            .optionalBindingType(Optional.of(bindingType))
+            .build();
+      case MULTIBOUND_SET:
+        return ((MultiboundSetBinding) this).toBuilder()
+            .optionalBindingType(Optional.of(bindingType))
+            .build();
+      default:
+        throw new AssertionError("Unexpected binding kind: " + kind());
+    }
+  }
+
   /**
    * Base builder for {@link com.google.auto.value.AutoValue @AutoValue} subclasses of {@link
    * ContributionBinding}.
    */
-  public abstract static class Builder<C extends ContributionBinding, B extends Builder<C, B>> {
+  abstract static class Builder<C extends ContributionBinding, B extends Builder<C, B>> {
     @CanIgnoreReturnValue
-    public abstract B dependencies(Iterable<DependencyRequest> dependencies);
+    abstract B unresolved(Optional<? extends Binding> unresolved);
 
     @CanIgnoreReturnValue
-    public B dependencies(DependencyRequest... dependencies) {
-      return dependencies(asList(dependencies));
-    }
-
-    @CanIgnoreReturnValue
-    public abstract B unresolved(C unresolved);
-
-    @CanIgnoreReturnValue
-    public abstract B contributionType(ContributionType contributionType);
-
-    @CanIgnoreReturnValue
-    public abstract B bindingElement(XElement bindingElement);
+    abstract B bindingElement(XElement bindingElement);
 
     @CanIgnoreReturnValue
     abstract B bindingElement(Optional<XElement> bindingElement);
 
     @CanIgnoreReturnValue
-    public final B clearBindingElement() {
+    final B clearBindingElement() {
       return bindingElement(Optional.empty());
     };
 
@@ -131,16 +165,10 @@
     abstract B contributingModule(XTypeElement contributingModule);
 
     @CanIgnoreReturnValue
-    public abstract B key(Key key);
+    abstract B key(Key key);
 
     @CanIgnoreReturnValue
-    public abstract B nullability(Nullability nullability);
-
-    @CanIgnoreReturnValue
-    abstract B mapKey(Optional<DaggerAnnotation> mapKey);
-
-    @CanIgnoreReturnValue
-    public abstract B kind(BindingKind kind);
+    abstract B scope(Optional<Scope> scope);
 
     abstract C build();
   }
diff --git a/java/dagger/internal/codegen/binding/Declaration.java b/java/dagger/internal/codegen/binding/Declaration.java
new file mode 100644
index 0000000..a980820
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/Declaration.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static dagger.internal.codegen.extension.Optionals.emptiesLast;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static java.util.Comparator.comparing;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.util.Comparator;
+import java.util.Optional;
+
+/** An object that declares or specifies a binding. */
+public abstract class Declaration {
+  /**
+   * A comparator that compares binding declarations with elements.
+   *
+   * <p>Compares, in order:
+   *
+   * <ol>
+   *   <li>Contributing module or enclosing type name
+   *   <li>Binding element's simple name
+   *   <li>Binding element's type
+   * </ol>
+   *
+   * Any binding declarations without elements are last.
+   */
+  public static final Comparator<Declaration> COMPARATOR =
+      comparing(
+              (Declaration declaration) ->
+                  declaration.contributingModule().isPresent()
+                      ? declaration.contributingModule()
+                      : declaration.bindingTypeElement(),
+              emptiesLast(comparing(XTypeElement::getQualifiedName)))
+          .thenComparing(
+              Declaration::bindingElement,
+              emptiesLast(
+                  comparing((XElement element) -> getSimpleName(element))
+                      .thenComparing(XElements::toStableString)));
+
+  /** The {@link Key} of this declaration. */
+  public abstract Key key();
+
+  /**
+   * The {@link XElement} that declares this binding. Absent for {@linkplain BindingKind binding
+   * kinds} that are not always declared by exactly one element.
+   *
+   * <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
+   * {@code @IntoSet} bindings for the same key will have a synthetic binding that depends on all
+   * contributions, but with no identifying binding element. A {@code @Multibinds} method will also
+   * contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
+   * the same component (and contribute to one single binding), it has no binding element.
+   */
+  public abstract Optional<XElement> bindingElement();
+
+  /**
+   * The type enclosing the {@link #bindingElement()}, or {@link Optional#empty()} if {@link
+   * #bindingElement()} is empty.
+   */
+  public final Optional<XTypeElement> bindingTypeElement() {
+    return bindingElement().map(XElements::closestEnclosingTypeElement);
+  }
+
+  /**
+   * The installed module class that contributed the {@link #bindingElement()}. May be a subclass of
+   * the class that contains {@link #bindingElement()}. Absent if {@link #bindingElement()} is
+   * empty.
+   */
+  public abstract Optional<XTypeElement> contributingModule();
+}
diff --git a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java b/java/dagger/internal/codegen/binding/DeclarationFormatter.java
similarity index 77%
rename from java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
rename to java/dagger/internal/codegen/binding/DeclarationFormatter.java
index d55886b..eaa8b4f 100644
--- a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
+++ b/java/dagger/internal/codegen/binding/DeclarationFormatter.java
@@ -32,27 +32,27 @@
 import javax.inject.Inject;
 
 /**
- * Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
+ * Formats a {@link Declaration} into a {@link String} suitable for use in error messages.
  */
-public final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
+public final class DeclarationFormatter extends Formatter<Declaration> {
   private final MethodSignatureFormatter methodSignatureFormatter;
 
   @Inject
-  BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter) {
+  DeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter) {
     this.methodSignatureFormatter = methodSignatureFormatter;
   }
 
   /**
    * Returns {@code true} for declarations that this formatter can format. Specifically bindings
-   * from subcomponent declarations or those with {@linkplain BindingDeclaration#bindingElement()
+   * from subcomponent declarations or those with {@linkplain Declaration#bindingElement()
    * binding elements} that are methods, constructors, or types.
    */
-  public boolean canFormat(BindingDeclaration bindingDeclaration) {
-    if (bindingDeclaration instanceof SubcomponentDeclaration) {
+  public boolean canFormat(Declaration declaration) {
+    if (declaration instanceof SubcomponentDeclaration) {
       return true;
     }
-    if (bindingDeclaration.bindingElement().isPresent()) {
-      XElement bindingElement = bindingDeclaration.bindingElement().get();
+    if (declaration.bindingElement().isPresent()) {
+      XElement bindingElement = declaration.bindingElement().get();
       return isMethodParameter(bindingElement)
           || isTypeElement(bindingElement)
           || isExecutable(bindingElement);
@@ -62,13 +62,13 @@
   }
 
   @Override
-  public String format(BindingDeclaration bindingDeclaration) {
-    if (bindingDeclaration instanceof SubcomponentDeclaration) {
-      return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration);
+  public String format(Declaration declaration) {
+    if (declaration instanceof SubcomponentDeclaration) {
+      return formatSubcomponentDeclaration((SubcomponentDeclaration) declaration);
     }
 
-    if (bindingDeclaration.bindingElement().isPresent()) {
-      XElement bindingElement = bindingDeclaration.bindingElement().get();
+    if (declaration.bindingElement().isPresent()) {
+      XElement bindingElement = declaration.bindingElement().get();
       if (isMethodParameter(bindingElement)) {
         return elementToString(bindingElement);
       } else if (isTypeElement(bindingElement)) {
@@ -77,14 +77,14 @@
       } else if (isExecutable(bindingElement)) {
         return methodSignatureFormatter.format(
             asExecutable(bindingElement),
-            bindingDeclaration.contributingModule().map(XTypeElement::getType));
+            declaration.contributingModule().map(XTypeElement::getType));
       }
       throw new IllegalArgumentException("Formatting unsupported for element: " + bindingElement);
     }
 
     return String.format(
         "Dagger-generated binding for %s",
-        stripCommonTypePrefixes(bindingDeclaration.key().toString()));
+        stripCommonTypePrefixes(declaration.key().toString()));
   }
 
   private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
diff --git a/java/dagger/internal/codegen/binding/DelegateBinding.java b/java/dagger/internal/codegen/binding/DelegateBinding.java
new file mode 100644
index 0000000..b6f7b9c
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/DelegateBinding.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#DELEGATE}. */
+@CheckReturnValue
+@AutoValue
+public abstract class DelegateBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.DELEGATE;
+  }
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of(delegateRequest());
+  }
+
+  /** Returns a request for the binding that this binding delegates to. */
+  abstract DependencyRequest delegateRequest();
+
+  @Override
+  public boolean requiresModuleInstance() {
+    return false;
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_DelegateBinding.Builder();
+  }
+
+  /** A {@link DelegateBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder extends ContributionBinding.Builder<DelegateBinding, Builder> {
+    abstract Builder delegateRequest(DependencyRequest delegateRequest);
+
+    abstract Builder optionalBindingType(Optional<BindingType> bindingType);
+
+    abstract Builder contributionType(ContributionType contributionType);
+
+    abstract Builder nullability(Nullability nullability);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/DelegateDeclaration.java b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
index 76d4287..c8365a8 100644
--- a/java/dagger/internal/codegen/binding/DelegateDeclaration.java
+++ b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
@@ -37,7 +37,7 @@
 
 /** The declaration for a delegate binding established by a {@link Binds} method. */
 @AutoValue
-public abstract class DelegateDeclaration extends BindingDeclaration
+public abstract class DelegateDeclaration extends Declaration
     implements HasContributionType {
   abstract DependencyRequest delegateRequest();
 
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
index a96eeda..bd16acc 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
@@ -21,13 +21,11 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.base.RequestKinds.frameworkClassName;
 import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
 import static dagger.internal.codegen.model.RequestKind.FUTURE;
 import static dagger.internal.codegen.model.RequestKind.INSTANCE;
 import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
-import static dagger.internal.codegen.model.RequestKind.PRODUCER;
 import static dagger.internal.codegen.model.RequestKind.PROVIDER;
 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
 import static dagger.internal.codegen.xprocessing.XTypes.unwrapType;
@@ -47,6 +45,7 @@
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.List;
 import java.util.Optional;
 import javax.inject.Inject;
@@ -104,21 +103,11 @@
         .build();
   }
 
-  // TODO(b/28555349): support PROVIDER_OF_LAZY here too
-  private static final ImmutableSet<RequestKind> WRAPPING_MAP_VALUE_FRAMEWORK_TYPES =
-      ImmutableSet.of(PROVIDER, PRODUCER);
-
   private RequestKind multibindingContributionRequestKind(
       Key multibindingKey, ContributionBinding multibindingContribution) {
     switch (multibindingContribution.contributionType()) {
       case MAP:
-        MapType mapType = MapType.from(multibindingKey);
-        for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) {
-          if (mapType.valuesAreTypeOf(frameworkClassName(kind))) {
-            return kind;
-          }
-        }
-        // fall through
+        return MapType.from(multibindingKey).valueRequestKind();
       case SET:
       case SET_VALUES:
         return INSTANCE;
@@ -206,15 +195,14 @@
    * Returns a synthetic request for the present value of an optional binding generated from a
    * {@link dagger.BindsOptionalOf} declaration.
    */
-  DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) {
+  DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey) {
     Optional<Key> key = keyFactory.unwrapOptional(requestKey);
     checkArgument(key.isPresent(), "not a request for optional: %s", requestKey);
+    RequestKind kind = getRequestKind(OptionalType.from(requestKey).valueType());
     return DependencyRequest.builder()
         .kind(kind)
         .key(key.get())
-        .isNullable(
-            requestKindImplicitlyAllowsNull(
-                getRequestKind(OptionalType.from(requestKey).valueType())))
+        .isNullable(requestKindImplicitlyAllowsNull(kind))
         .build();
   }
 
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
index 853ee99..20f0b12 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
@@ -21,11 +21,16 @@
 import static androidx.room.compiler.processing.XElementKt.isVariableElement;
 import static dagger.internal.codegen.base.ElementFormatter.elementToString;
 import static dagger.internal.codegen.base.RequestKinds.requestType;
+import static java.util.stream.Collectors.joining;
 
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XProcessingEnv;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableCollection;
 import dagger.internal.codegen.base.Formatter;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Node;
 import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.xprocessing.XTypes;
@@ -58,12 +63,33 @@
     this.processingEnv = processingEnv;
   }
 
+  public String formatEdges(ImmutableCollection<DependencyEdge> edges, BindingGraph graph) {
+    return edges.stream()
+        .map(edge -> formatEdge(edge, graph))
+        .filter(line -> !line.isEmpty())
+        .collect(joining("\n"));
+  }
+
+  public String formatEdge(DependencyEdge edge, BindingGraph graph) {
+    Node sourceNode = graph.network().incidentNodes(edge).source();
+    XTypeElement sourceComponent = sourceNode.componentPath().currentComponent().xprocessing();
+    return format(Optional.of(sourceComponent), edge.dependencyRequest());
+  }
+
   @Override
   public String format(DependencyRequest request) {
+    return format(Optional.empty(), request);
+  }
+
+  private  String format(Optional<XTypeElement> optionalComponent, DependencyRequest request) {
     if (!request.requestElement().isPresent()) {
       return "";
     }
     XElement requestElement = request.requestElement().get().xprocessing();
+    String componentReference =
+        optionalComponent
+            .map(component -> String.format("[%s] ", component.getQualifiedName()))
+            .orElse("");
     if (isMethod(requestElement)) {
       return INDENT
           + request.key()
@@ -71,6 +97,7 @@
           + componentMethodRequestVerb(request)
           + " at\n"
           + DOUBLE_INDENT
+          + componentReference
           + elementToString(requestElement);
     } else if (isVariableElement(requestElement)) {
       return INDENT
@@ -79,6 +106,7 @@
               requestType(request.kind(), request.key().type().xprocessing(), processingEnv))
           + " is injected at\n"
           + DOUBLE_INDENT
+          + componentReference
           + elementToString(requestElement);
     } else if (isTypeElement(requestElement)) {
       return ""; // types by themselves provide no useful information.
@@ -87,21 +115,7 @@
     }
   }
 
-  /**
-   * Appends a newline and the formatted dependency request unless {@link
-   * #format(DependencyRequest)} returns the empty string.
-   */
-  @CanIgnoreReturnValue
-  public StringBuilder appendFormatLine(
-      StringBuilder builder, DependencyRequest dependencyRequest) {
-    String formatted = format(dependencyRequest);
-    if (!formatted.isEmpty()) {
-      builder.append('\n').append(formatted);
-    }
-    return builder;
-  }
-
-  private String formatQualifier(Optional<DaggerAnnotation> maybeQualifier) {
+  private static String formatQualifier(Optional<DaggerAnnotation> maybeQualifier) {
     return maybeQualifier.map(qualifier -> qualifier + " ").orElse("");
   }
 
@@ -109,7 +123,7 @@
    * Returns the verb for a component method dependency request. Returns "produced", "provided", or
    * "injected", depending on the kind of request.
    */
-  private String componentMethodRequestVerb(DependencyRequest request) {
+  private static String componentMethodRequestVerb(DependencyRequest request) {
     switch (request.kind()) {
       case FUTURE:
       case PRODUCER:
diff --git a/java/dagger/internal/codegen/binding/FrameworkField.java b/java/dagger/internal/codegen/binding/FrameworkField.java
index a9f3bbf..bb51968 100644
--- a/java/dagger/internal/codegen/binding/FrameworkField.java
+++ b/java/dagger/internal/codegen/binding/FrameworkField.java
@@ -20,18 +20,17 @@
 import static androidx.room.compiler.processing.XElementKt.isMethod;
 import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
 import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static com.google.common.collect.Iterables.getLast;
 import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTOR;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 
+import androidx.room.compiler.codegen.XClassName;
+import androidx.room.compiler.codegen.XTypeName;
 import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
 import com.google.auto.value.AutoValue;
 import com.google.common.base.CaseFormat;
-import com.google.common.base.Preconditions;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
 import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.javapoet.TypeNames;
 import java.util.Optional;
 
 /**
@@ -51,18 +50,13 @@
   /**
    * Creates a framework field.
    *
-   * @param fieldType the type of the framework field (e.g., {@code Provider<Foo>}).
    * @param fieldName the base name of the field. The name of the raw type of the field will be
    *     added as a suffix
+   * @param frameworkClassName the framework class that wraps the type (e.g., {@code Provider}).
+   * @param type the base type of the field (e.g., {@code Foo}).
    */
-  public static FrameworkField create(TypeName fieldType, String fieldName) {
-    Preconditions.checkState(
-        fieldType instanceof ClassName || fieldType instanceof ParameterizedTypeName,
-        "Can only create a field with a class name or parameterized type name");
-    String suffix = ((ClassName) TypeNames.rawTypeName(fieldType)).simpleName();
-    return new AutoValue_FrameworkField(
-        fieldType,
-        fieldName.endsWith(suffix) ? fieldName : fieldName + suffix);
+  public static FrameworkField create(String fieldName, XClassName frameworkClassName, XType type) {
+    return createInternal(fieldName, frameworkClassName, Optional.of(type));
   }
 
   /**
@@ -72,15 +66,24 @@
    *     one for the binding's type.
    */
   public static FrameworkField forBinding(
-      ContributionBinding binding, Optional<ClassName> frameworkClassName) {
-    return create(
-        fieldType(binding, frameworkClassName.orElse(binding.frameworkType().frameworkClassName())),
-        frameworkFieldName(binding));
+      ContributionBinding binding, Optional<XClassName> frameworkClassName) {
+    return createInternal(
+        bindingName(binding),
+        frameworkClassName.orElse(binding.frameworkType().frameworkClassName()),
+        bindingType(binding));
   }
 
-  private static TypeName fieldType(ContributionBinding binding, ClassName frameworkClassName) {
+  private static String bindingName(ContributionBinding binding) {
+    if (binding.bindingElement().isPresent()) {
+      String name = bindingElementName(binding.bindingElement().get());
+      return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name;
+    }
+    return KeyVariableNamer.name(binding.key());
+  }
+
+  private static Optional<XType> bindingType(ContributionBinding binding) {
     if (binding.contributionType().isMultibinding()) {
-      return ParameterizedTypeName.get(frameworkClassName, binding.contributedType().getTypeName());
+      return Optional.of(binding.contributedType());
     }
 
     // If the binding key type is a Map<K, Provider<V>>, we need to change field type to a raw
@@ -89,19 +92,25 @@
     // Map<K, javax.inject.Provider<V>>. We could add casts everywhere, but it is easier to just
     // make the field itself a raw type.
     if (MapType.isMapOfProvider(binding.contributedType())) {
-      return frameworkClassName;
+      return Optional.empty();
     }
 
-    return ParameterizedTypeName.get(
-        frameworkClassName, binding.key().type().xprocessing().getTypeName());
+    return Optional.of(binding.key().type().xprocessing());
   }
 
-  private static String frameworkFieldName(ContributionBinding binding) {
-    if (binding.bindingElement().isPresent()) {
-      String name = bindingElementName(binding.bindingElement().get());
-      return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name;
-    }
-    return KeyVariableNamer.name(binding.key());
+  private static FrameworkField createInternal(
+      String fieldName, XClassName frameworkClassName, Optional<XType> type) {
+    return new AutoValue_FrameworkField(
+        frameworkFieldName(fieldName, frameworkClassName),
+        type.isPresent()
+            ? frameworkClassName.parametrizedBy(type.get().asTypeName())
+            // Use a raw framework classname, e.g. Provider
+            : frameworkClassName);
+  }
+
+  private static String frameworkFieldName(String fieldName, XClassName frameworkClassName) {
+    String suffix = getLast(frameworkClassName.getSimpleNames());
+    return fieldName.endsWith(suffix) ? fieldName : fieldName + suffix;
   }
 
   private static String bindingElementName(XElement bindingElement) {
@@ -118,7 +127,7 @@
     }
   }
 
-  public abstract TypeName type();
-
   public abstract String name();
+
+  public abstract XTypeName type();
 }
diff --git a/java/dagger/internal/codegen/binding/FrameworkType.java b/java/dagger/internal/codegen/binding/FrameworkType.java
index c995948..bc4c8ce 100644
--- a/java/dagger/internal/codegen/binding/FrameworkType.java
+++ b/java/dagger/internal/codegen/binding/FrameworkType.java
@@ -16,11 +16,12 @@
 
 package dagger.internal.codegen.binding;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
 
+import androidx.room.compiler.codegen.XClassName;
 import androidx.room.compiler.processing.XProcessingEnv;
-import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.ParameterizedTypeName;
 import com.squareup.javapoet.TypeName;
@@ -29,6 +30,7 @@
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.xprocessing.XTypeNames;
 import java.util.Optional;
 
 /** One of the core types initialized as fields in a generated component. */
@@ -142,9 +144,7 @@
                   from.codeBlock()));
 
         case PRODUCER:
-          return Expression.create(from.type(), to(
-              requestKind,
-              from.codeBlock()));
+          return from;
 
         default:
           throw new IllegalArgumentException(
@@ -170,28 +170,30 @@
     switch (requestKind) {
       case PROVIDER:
         return Optional.of(FrameworkType.PROVIDER);
+      case PRODUCER:
+        return Optional.of(FrameworkType.PRODUCER_NODE);
       default:
         return Optional.empty();
     }
   }
 
   /** The class of fields of this type. */
-  public ClassName frameworkClassName() {
+  public XClassName frameworkClassName() {
     switch (this) {
       case PROVIDER:
-        return TypeNames.DAGGER_PROVIDER;
+        return XTypeNames.DAGGER_PROVIDER;
       case PRODUCER_NODE:
         // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
         // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
         // made to not implement Producer.
-        return TypeNames.PRODUCER;
+        return XTypeNames.PRODUCER;
     }
     throw new AssertionError("Unknown value: " + this.name());
   }
 
   /** Returns the {@link #frameworkClassName()} parameterized with a type. */
   public ParameterizedTypeName frameworkClassOf(TypeName valueType) {
-    return ParameterizedTypeName.get(frameworkClassName(), valueType);
+    return ParameterizedTypeName.get(toJavaPoet(frameworkClassName()), valueType);
   }
 
   /** The request kind that an instance of this framework type can satisfy directly, if any. */
diff --git a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
index 45fea0a..46d57f7 100644
--- a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
+++ b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
@@ -36,10 +36,9 @@
  */
 public interface InjectBindingRegistry {
   /**
-   * Returns a {@link ProvisionBinding} for {@code key}. If none has been registered yet, registers
-   * one.
+   * Returns an injection binding for {@code key}. If none has been registered yet, registers one.
    */
-  Optional<ProvisionBinding> getOrFindProvisionBinding(Key key);
+  Optional<ContributionBinding> getOrFindInjectionBinding(Key key);
 
   /**
    * Returns a {@link MembersInjectionBinding} for {@code key}. If none has been registered yet,
@@ -48,13 +47,14 @@
   Optional<MembersInjectionBinding> getOrFindMembersInjectionBinding(Key key);
 
   /**
-   * Returns a {@link ProvisionBinding} for a {@link dagger.MembersInjector} of {@code key}. If none
-   * has been registered yet, registers one.
+   * Returns a {@link MembersInjectorBinding} for {@code key}. If none has been registered yet,
+   * registers one.
    */
-  Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key);
+  Optional<MembersInjectorBinding> getOrFindMembersInjectorBinding(Key key);
 
   @CanIgnoreReturnValue
-  Optional<ProvisionBinding> tryRegisterInjectConstructor(XConstructorElement constructorElement);
+  Optional<ContributionBinding> tryRegisterInjectConstructor(
+      XConstructorElement constructorElement);
 
   @CanIgnoreReturnValue
   Optional<MembersInjectionBinding> tryRegisterInjectField(XFieldElement fieldElement);
@@ -64,11 +64,11 @@
 
   /**
    * This method ensures that sources for all registered {@link Binding bindings} (either explicitly
-   * or implicitly via {@link #getOrFindMembersInjectionBinding} or {@link
-   * #getOrFindProvisionBinding}) are generated.
+   * or implicitly via {@link #getOrFindMembersInjectionBinding} or
+   * {@link #getOrFindInjectionBinding}) are generated.
    */
   void generateSourcesForRequiredBindings(
-      SourceFileGenerator<ProvisionBinding> factoryGenerator,
+      SourceFileGenerator<ContributionBinding> factoryGenerator,
       SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
       throws SourceFileGenerationException;
 }
diff --git a/java/dagger/internal/codegen/binding/InjectionAnnotations.java b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
index d4e1f90..13abe8b 100644
--- a/java/dagger/internal/codegen/binding/InjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
@@ -36,6 +36,7 @@
 import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
 
+import androidx.room.compiler.codegen.XClassName;
 import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XConstructorElement;
 import androidx.room.compiler.processing.XElement;
@@ -45,7 +46,6 @@
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
 import dagger.internal.codegen.base.DaggerSuperficialValidation;
 import dagger.internal.codegen.base.ElementFormatter;
 import dagger.internal.codegen.compileroption.CompilerOptions;
@@ -54,6 +54,7 @@
 import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.model.Scope;
 import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XTypeNames;
 import java.util.Optional;
 import java.util.stream.Stream;
 import javax.inject.Inject;
@@ -165,10 +166,10 @@
   private Optional<XAnnotation> getScopeMetadata(XElement element) {
     return getGeneratedNameForScopeMetadata(element)
         .flatMap(factoryName -> Optional.ofNullable(processingEnv.findTypeElement(factoryName)))
-        .flatMap(factory -> Optional.ofNullable(factory.getAnnotation(TypeNames.SCOPE_METADATA)));
+        .flatMap(factory -> Optional.ofNullable(factory.getAnnotation(XTypeNames.SCOPE_METADATA)));
   }
 
-  private Optional<ClassName> getGeneratedNameForScopeMetadata(XElement element) {
+  private Optional<XClassName> getGeneratedNameForScopeMetadata(XElement element) {
     // Currently, we only support ScopeMetadata for inject-constructor types and provides methods.
     if (isTypeElement(element)) {
       return asTypeElement(element).getConstructors().stream()
@@ -297,10 +298,10 @@
   private Optional<XAnnotation> getQualifierMetadata(XElement element) {
     return getGeneratedNameForQualifierMetadata(element)
         .flatMap(name -> Optional.ofNullable(processingEnv.findTypeElement(name)))
-        .flatMap(type -> Optional.ofNullable(type.getAnnotation(TypeNames.QUALIFIER_METADATA)));
+        .flatMap(type -> Optional.ofNullable(type.getAnnotation(XTypeNames.QUALIFIER_METADATA)));
   }
 
-  private Optional<ClassName> getGeneratedNameForQualifierMetadata(XElement element) {
+  private Optional<XClassName> getGeneratedNameForQualifierMetadata(XElement element) {
     // Currently we only support @QualifierMetadata for @Inject fields, @Inject method parameters,
     // @Inject constructor parameters, @Provides methods, and @Provides method parameters.
     if (isField(element) && hasInjectAnnotation(element)) {
@@ -349,8 +350,7 @@
     return element.hasAnyAnnotation(TypeNames.INJECT, TypeNames.INJECT_JAVAX);
   }
 
-  /** Returns true if the given element is annotated with {@link Inject}. */
-  public static boolean hasInjectOrAssistedInjectAnnotation(XElement element) {
+  private static boolean hasInjectOrAssistedInjectAnnotation(XElement element) {
     return element.hasAnyAnnotation(
         TypeNames.INJECT, TypeNames.INJECT_JAVAX, TypeNames.ASSISTED_INJECT);
   }
diff --git a/java/dagger/internal/codegen/binding/InjectionBinding.java b/java/dagger/internal/codegen/binding/InjectionBinding.java
new file mode 100644
index 0000000..657b392
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/InjectionBinding.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#INJECTION}. */
+@CheckReturnValue
+@AutoValue
+public abstract class InjectionBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.INJECTION;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  /** Dependencies necessary to invoke the {@code @Inject} annotated constructor. */
+  public abstract ImmutableSet<DependencyRequest> constructorDependencies();
+
+  /** {@link InjectionSite}s for all {@code @Inject} members. */
+  public abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.<DependencyRequest>builder()
+        .addAll(constructorDependencies())
+        .addAll(
+            injectionSites().stream()
+                .flatMap(i -> i.dependencies().stream())
+                .collect(toImmutableSet()))
+        .build();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_InjectionBinding.Builder();
+  }
+
+  /** A {@link InjectionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder extends ContributionBinding.Builder<InjectionBinding, Builder> {
+    abstract Builder constructorDependencies(Iterable<DependencyRequest> constructorDependencies);
+
+    abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/KeyFactory.java b/java/dagger/internal/codegen/binding/KeyFactory.java
index d7f78c1..693382e 100644
--- a/java/dagger/internal/codegen/binding/KeyFactory.java
+++ b/java/dagger/internal/codegen/binding/KeyFactory.java
@@ -24,12 +24,9 @@
 import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
 import static dagger.internal.codegen.binding.MapKeys.getMapKey;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.Optionals.firstPresent;
 import static dagger.internal.codegen.javapoet.TypeNames.isFutureType;
 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
 import static dagger.internal.codegen.xprocessing.XTypes.unwrapType;
-import static java.util.Arrays.asList;
 
 import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XMethodElement;
@@ -37,7 +34,6 @@
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
-import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import dagger.Binds;
 import dagger.BindsOptionalOf;
@@ -47,6 +43,7 @@
 import dagger.internal.codegen.base.OptionalType;
 import dagger.internal.codegen.base.RequestKinds;
 import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.model.DaggerExecutableElement;
@@ -56,19 +53,22 @@
 import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.xprocessing.XAnnotations;
 import dagger.multibindings.Multibinds;
-import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Stream;
 import javax.inject.Inject;
 
 /** A factory for {@link Key}s. */
 public final class KeyFactory {
   private final XProcessingEnv processingEnv;
+  private final CompilerOptions compilerOptions;
   private final InjectionAnnotations injectionAnnotations;
 
   @Inject
-  KeyFactory(XProcessingEnv processingEnv, InjectionAnnotations injectionAnnotations) {
+  KeyFactory(
+      XProcessingEnv processingEnv,
+      CompilerOptions compilerOptions,
+      InjectionAnnotations injectionAnnotations) {
     this.processingEnv = processingEnv;
+    this.compilerOptions = compilerOptions;
     this.injectionAnnotations = injectionAnnotations;
   }
 
@@ -82,8 +82,23 @@
         processingEnv.requireTypeElement(TypeNames.MAP), keyType.boxed(), valueType.boxed());
   }
 
+  /**
+   * If {@code key}'s type is {@code Optional<T>} for some {@code T}, returns a key with the same
+   * qualifier whose type is {@linkplain RequestKinds#extractKeyType(RequestKind, XType)}
+   * extracted} from {@code T}.
+   */
+  Key optionalOf(Key key) {
+    return key.withType(DaggerType.from(optionalOf(key.type().xprocessing())));
+  }
+
+  private XType optionalOf(XType type) {
+    return processingEnv.getDeclaredType(
+        processingEnv.requireTypeElement(TypeNames.JDK_OPTIONAL), type.boxed());
+  }
+
   /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
   private XType mapOfFrameworkType(XType keyType, ClassName frameworkClassName, XType valueType) {
+    checkArgument(FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES.contains(frameworkClassName));
     return mapOf(
         keyType,
         processingEnv.getDeclaredType(
@@ -113,10 +128,12 @@
   }
 
   public Key forProvidesMethod(XMethodElement method, XTypeElement contributingModule) {
+    checkArgument(method.hasAnnotation(TypeNames.PROVIDES));
     return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PROVIDER));
   }
 
   public Key forProducesMethod(XMethodElement method, XTypeElement contributingModule) {
+    checkArgument(method.hasAnnotation(TypeNames.PRODUCES));
     return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PRODUCER));
   }
 
@@ -205,7 +222,8 @@
             method.getAllAnnotations().stream()
                 .map(XAnnotations::toString)
                 .collect(toImmutableList()));
-        return frameworkClassName.isPresent()
+        return (frameworkClassName.isPresent()
+                && compilerOptions.useFrameworkTypeInMapMultibindingContributionKey())
             ? mapOfFrameworkType(mapKeyType.get(), frameworkClassName.get(), returnType)
             : mapOf(mapKeyType.get(), returnType);
       case SET_VALUES:
@@ -219,12 +237,14 @@
   /**
    * Returns the key for a binding associated with a {@link DelegateDeclaration}.
    *
-   * <p>If {@code delegateDeclaration} is {@code @IntoMap}, transforms the {@code Map<K, V>} key
-   * from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code
-   * delegateDeclaration} is not a map contribution, its key is returned.
+   * <p>If {@code delegateDeclaration} is a multibinding map contribution and
+   * {@link CompilerOptions#useFrameworkTypeInMapMultibindingContributionKey()} is enabled, then
+   * transforms the {@code Map<K, V>} key into {@code Map<K, FrameworkType<V>>}, otherwise returns
+   * the unaltered key.
    */
   Key forDelegateBinding(DelegateDeclaration delegateDeclaration, ClassName frameworkType) {
     return delegateDeclaration.contributionType().equals(ContributionType.MAP)
+            && compilerOptions.useFrameworkTypeInMapMultibindingContributionKey()
         ? wrapMapValue(delegateDeclaration.key(), frameworkType)
         : delegateDeclaration.key();
   }
@@ -268,40 +288,6 @@
   }
 
   /**
-   * If {@code requestKey} is for a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns keys
-   * for {@code Map<K, Provider<V>>} and {@code Map<K, Producer<V>>} (if Dagger-Producers is on the
-   * classpath).
-   */
-  ImmutableSet<Key> implicitFrameworkMapKeys(Key requestKey) {
-    return Stream.of(implicitMapProviderKeyFrom(requestKey), implicitMapProducerKeyFrom(requestKey))
-        .filter(Optional::isPresent)
-        .map(Optional::get)
-        .collect(toImmutableSet());
-  }
-
-  /**
-   * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key
-   * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code <K,
-   * V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be returned.
-   */
-  Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
-    return firstPresent(
-        rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PROVIDER),
-        wrapMapKey(possibleMapKey, TypeNames.PROVIDER));
-  }
-
-  /**
-   * Optionally extract a {@link Key} for the underlying production binding(s) if such a valid key
-   * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code <K,
-   * V>} or {@code Map<K, Produced<V>>}, a key of {@code Map<K, Producer<V>>} will be returned.
-   */
-  Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
-    return firstPresent(
-        rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PRODUCER),
-        wrapMapKey(possibleMapKey, TypeNames.PRODUCER));
-  }
-
-  /**
    * If {@code key}'s type is {@code Map<K, Provider<V>>}, {@code Map<K, Producer<V>>}, or {@code
    * Map<K, Produced<V>>}, returns a key with the same qualifier and {@link
    * Key#multibindingContributionIdentifier()} whose type is simply {@code Map<K, V>}.
@@ -311,82 +297,41 @@
   public Key unwrapMapValueType(Key key) {
     if (MapType.isMap(key)) {
       MapType mapType = MapType.from(key);
-      if (!mapType.isRawType()) {
-        for (ClassName frameworkClass :
-            asList(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED)) {
-          if (mapType.valuesAreTypeOf(frameworkClass)) {
-            return key.withType(
-                DaggerType.from(
-                    mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass))));
-          }
-        }
+      if (!mapType.isRawType() && mapType.valuesAreFrameworkType()) {
+        return key.withType(
+            DaggerType.from(mapOf(mapType.keyType(), mapType.unwrappedFrameworkValueType())));
       }
     }
     return key;
   }
 
-  /** Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}. */
-  private Key wrapMapValue(Key key, ClassName newWrappingClassName) {
-    checkArgument(FrameworkTypes.isFrameworkType(processingEnv.requireType(newWrappingClassName)));
-    return wrapMapKey(key, newWrappingClassName).get();
-  }
-
   /**
-   * If {@code key}'s type is {@code Map<K, CurrentWrappingClass<Bar>>}, returns a key with type
-   * {@code Map<K, NewWrappingClass<Bar>>} with the same qualifier. Otherwise returns {@link
-   * Optional#empty()}.
+   * Returns a key with the type {@code Map<K, FrameworkType<V>>} if the given key has a type of
+   * {@code Map<K, V>}. Otherwise, returns the unaltered key.
    *
-   * <p>Returns {@link Optional#empty()} if {@code newWrappingClass} is not in the classpath.
-   *
-   * @throws IllegalArgumentException if {@code newWrappingClass} is the same as {@code
-   *     currentWrappingClass}
+   * @throws IllegalArgumentException if the {@code frameworkClassName} is not a valid framework
+   * type for multibinding maps.
+   * @throws IllegalStateException if the {@code key} is already wrapped in a (different) framework
+   * type.
    */
-  public Optional<Key> rewrapMapKey(
-      Key possibleMapKey, ClassName currentWrappingClassName, ClassName newWrappingClassName) {
-    checkArgument(!currentWrappingClassName.equals(newWrappingClassName));
-    if (MapType.isMap(possibleMapKey)) {
-      MapType mapType = MapType.from(possibleMapKey);
-      if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClassName)) {
-        XTypeElement wrappingElement = processingEnv.findTypeElement(newWrappingClassName);
-        if (wrappingElement == null) {
+  private Key wrapMapValue(Key key, ClassName frameworkClassName) {
+    checkArgument(FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES.contains(frameworkClassName));
+    if (MapType.isMap(key)) {
+      MapType mapType = MapType.from(key);
+      if (!mapType.isRawType() && !mapType.valuesAreTypeOf(frameworkClassName)) {
+        checkState(!mapType.valuesAreFrameworkType());
+        XTypeElement frameworkTypeElement = processingEnv.findTypeElement(frameworkClassName);
+        if (frameworkTypeElement == null) {
           // This target might not be compiled with Producers, so wrappingClass might not have an
           // associated element.
-          return Optional.empty();
+          return key;
         }
         XType wrappedValueType =
-            processingEnv.getDeclaredType(
-                wrappingElement, mapType.unwrappedValueType(currentWrappingClassName));
-        return Optional.of(
-            possibleMapKey.withType(DaggerType.from(mapOf(mapType.keyType(), wrappedValueType))));
+            processingEnv.getDeclaredType(frameworkTypeElement, mapType.valueType());
+        return key.withType(DaggerType.from(mapOf(mapType.keyType(), wrappedValueType)));
       }
     }
-    return Optional.empty();
-  }
-
-  /**
-   * If {@code key}'s type is {@code Map<K, Foo>} and {@code Foo} is not {@code WrappingClass
-   * <Bar>}, returns a key with type {@code Map<K, WrappingClass<Foo>>} with the same qualifier.
-   * Otherwise returns {@link Optional#empty()}.
-   *
-   * <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath.
-   */
-  private Optional<Key> wrapMapKey(Key possibleMapKey, ClassName wrappingClassName) {
-    if (MapType.isMap(possibleMapKey)) {
-      MapType mapType = MapType.from(possibleMapKey);
-      if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClassName)) {
-        XTypeElement wrappingElement = processingEnv.findTypeElement(wrappingClassName);
-        if (wrappingElement == null) {
-          // This target might not be compiled with Producers, so wrappingClass might not have an
-          // associated element.
-          return Optional.empty();
-        }
-        XType wrappedValueType =
-            processingEnv.getDeclaredType(wrappingElement, mapType.valueType());
-        return Optional.of(
-            possibleMapKey.withType(DaggerType.from(mapOf(mapType.keyType(), wrappedValueType))));
-      }
-    }
-    return Optional.empty();
+    return key;
   }
 
   /**
diff --git a/java/dagger/internal/codegen/binding/BindingGraphConverter.java b/java/dagger/internal/codegen/binding/LegacyBindingGraphConverter.java
similarity index 70%
rename from java/dagger/internal/codegen/binding/BindingGraphConverter.java
rename to java/dagger/internal/codegen/binding/LegacyBindingGraphConverter.java
index adb4435..fd86dd9 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphConverter.java
+++ b/java/dagger/internal/codegen/binding/LegacyBindingGraphConverter.java
@@ -23,16 +23,13 @@
 
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.graph.ImmutableNetwork;
 import com.google.common.graph.MutableNetwork;
 import com.google.common.graph.NetworkBuilder;
-import dagger.internal.codegen.binding.BindingGraph.TopLevelBindingGraph;
-import dagger.internal.codegen.binding.BindingGraphFactory.LegacyBindingGraph;
 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.binding.LegacyBindingGraphFactory.LegacyBindingGraph;
+import dagger.internal.codegen.binding.LegacyBindingGraphFactory.LegacyResolvedBindings;
 import dagger.internal.codegen.model.BindingGraph.ComponentNode;
 import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
 import dagger.internal.codegen.model.BindingGraph.Edge;
@@ -41,30 +38,23 @@
 import dagger.internal.codegen.model.ComponentPath;
 import dagger.internal.codegen.model.DaggerTypeElement;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.model.Key;
 import java.util.ArrayDeque;
 import java.util.Deque;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import javax.inject.Inject;
 
 /** Converts {@link BindingGraph}s to {@link dagger.internal.codegen.model.BindingGraph}s. */
-final class BindingGraphConverter {
-  private final BindingDeclarationFormatter bindingDeclarationFormatter;
-
+final class LegacyBindingGraphConverter {
   @Inject
-  BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
-    this.bindingDeclarationFormatter = bindingDeclarationFormatter;
-  }
+  LegacyBindingGraphConverter() {}
 
   /**
    * Creates the external {@link dagger.internal.codegen.model.BindingGraph} representing the given
    * internal {@link BindingGraph}.
    */
   BindingGraph convert(LegacyBindingGraph legacyBindingGraph, boolean isFullBindingGraph) {
-    MutableNetwork<Node, Edge> network = asNetwork(legacyBindingGraph);
+    MutableNetwork<Node, Edge> network = Converter.convertToNetwork(legacyBindingGraph);
     ComponentNode rootNode = legacyBindingGraph.componentNode();
 
     // When bindings are copied down into child graphs because they transitively depend on local
@@ -76,18 +66,18 @@
       unreachableNodes(network.asGraph(), rootNode).forEach(network::removeNode);
     }
 
-    TopLevelBindingGraph topLevelBindingGraph =
-        TopLevelBindingGraph.create(ImmutableNetwork.copyOf(network), isFullBindingGraph);
-    return BindingGraph.create(rootNode, topLevelBindingGraph);
+    return BindingGraph.create(
+        ImmutableNetwork.copyOf(network),
+        isFullBindingGraph);
   }
 
-  private MutableNetwork<Node, Edge> asNetwork(LegacyBindingGraph graph) {
-    Converter converter = new Converter();
-    converter.visitRootComponent(graph);
-    return converter.network;
-  }
+  private static final class Converter {
+    static MutableNetwork<Node, Edge> convertToNetwork(LegacyBindingGraph graph) {
+      Converter converter = new Converter();
+      converter.visitRootComponent(graph);
+      return converter.network;
+    }
 
-  private final class Converter {
     /** The path from the root graph to the currently visited graph. */
     private final Deque<LegacyBindingGraph> bindingGraphPath = new ArrayDeque<>();
 
@@ -95,9 +85,6 @@
         NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
     private final Set<BindingNode> bindings = new HashSet<>();
 
-    private final Map<ResolvedBindings, ImmutableSet<BindingNode>> resolvedBindingsMap =
-        new HashMap<>();
-
     private void visitRootComponent(LegacyBindingGraph graph) {
       visitComponent(graph);
     }
@@ -127,8 +114,8 @@
         addDependencyEdges(graph.componentNode(), entryPointMethod.dependencyRequest().get());
       }
 
-      for (ResolvedBindings resolvedBindings : graph.resolvedBindings()) {
-        for (BindingNode binding : bindingNodes(resolvedBindings)) {
+      for (LegacyResolvedBindings resolvedBindings : graph.resolvedBindings()) {
+        for (BindingNode binding : resolvedBindings.bindingNodes()) {
           if (bindings.add(binding)) {
             network.addNode(binding);
             for (DependencyRequest dependencyRequest : binding.dependencies()) {
@@ -140,8 +127,7 @@
             network.addEdge(
                 binding,
                 subcomponentNode(binding.key().type().xprocessing(), graph),
-                new SubcomponentCreatorBindingEdgeImpl(
-                    resolvedBindings.subcomponentDeclarations()));
+                new SubcomponentCreatorBindingEdgeImpl(binding.subcomponentDeclarations()));
           }
         }
       }
@@ -171,21 +157,6 @@
     }
 
     /**
-     * Returns the subpath from the root component to the matching {@code ancestor} of the current
-     * component.
-     */
-    private ComponentPath pathFromRootToAncestor(XTypeElement ancestor) {
-      for (LegacyBindingGraph graph : bindingGraphPath) {
-        if (graph.componentDescriptor().typeElement().equals(ancestor)) {
-          return graph.componentPath();
-        }
-      }
-      throw new IllegalArgumentException(
-          String.format(
-              "%s is not in the current path: %s", ancestor.getQualifiedName(), componentPath()));
-    }
-
-    /**
      * Returns the LegacyBindingGraph for {@code ancestor}, where {@code ancestor} is in the
      * component path of the current traversal.
      */
@@ -205,11 +176,11 @@
      * binding(s) that satisfy a dependency request.
      */
     private void addDependencyEdges(Node source, DependencyRequest dependencyRequest) {
-      ResolvedBindings dependencies = resolvedDependencies(source, dependencyRequest);
+      LegacyResolvedBindings dependencies = resolvedDependencies(source, dependencyRequest);
       if (dependencies.isEmpty()) {
         addDependencyEdge(source, dependencyRequest, missingBindingNode(dependencies));
       } else {
-        for (BindingNode dependency : bindingNodes(dependencies)) {
+        for (BindingNode dependency : dependencies.bindingNodes()) {
           addDependencyEdge(source, dependencyRequest, dependency);
         }
       }
@@ -243,42 +214,13 @@
       return false;
     }
 
-    private ResolvedBindings resolvedDependencies(
+    private LegacyResolvedBindings resolvedDependencies(
         Node source, DependencyRequest dependencyRequest) {
       return graphForAncestor(source.componentPath().currentComponent().xprocessing())
           .resolvedBindings(bindingRequest(dependencyRequest));
     }
 
-    private ImmutableSet<BindingNode> bindingNodes(ResolvedBindings resolvedBindings) {
-      return resolvedBindingsMap.computeIfAbsent(resolvedBindings, this::uncachedBindingNodes);
-    }
-
-    private ImmutableSet<BindingNode> uncachedBindingNodes(ResolvedBindings resolvedBindings) {
-      ImmutableSet.Builder<BindingNode> bindingNodes = ImmutableSet.builder();
-      resolvedBindings
-          .allBindings()
-          .asMap()
-          .forEach(
-              (component, bindings) -> {
-                for (Binding binding : bindings) {
-                  bindingNodes.add(bindingNode(resolvedBindings, binding, component));
-                }
-              });
-      return bindingNodes.build();
-    }
-
-    private BindingNode bindingNode(
-        ResolvedBindings resolvedBindings, Binding binding, XTypeElement owningComponent) {
-      return BindingNode.create(
-          pathFromRootToAncestor(owningComponent),
-          binding,
-          resolvedBindings.multibindingDeclarations(),
-          resolvedBindings.optionalBindingDeclarations(),
-          resolvedBindings.subcomponentDeclarations(),
-          bindingDeclarationFormatter);
-    }
-
-    private MissingBinding missingBindingNode(ResolvedBindings dependencies) {
+    private MissingBinding missingBindingNode(LegacyResolvedBindings dependencies) {
       // Put all missing binding nodes in the root component. This simplifies the binding graph
       // and produces better error messages for users since all dependents point to the same node.
       return MissingBindingImpl.create(
@@ -296,18 +238,4 @@
           subcomponent);
     }
   }
-
-  @AutoValue
-  abstract static class MissingBindingImpl extends MissingBinding {
-    static MissingBinding create(ComponentPath component, Key key) {
-      return new AutoValue_BindingGraphConverter_MissingBindingImpl(component, key);
-    }
-
-    @Memoized
-    @Override
-    public abstract int hashCode();
-
-    @Override
-    public abstract boolean equals(Object o);
-  }
 }
diff --git a/java/dagger/internal/codegen/binding/LegacyBindingGraphFactory.java b/java/dagger/internal/codegen/binding/LegacyBindingGraphFactory.java
new file mode 100644
index 0000000..4e95c2e
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/LegacyBindingGraphFactory.java
@@ -0,0 +1,892 @@
+/*
+ * Copyright (C) 2014 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
+import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
+import static java.util.function.Predicate.isEqual;
+
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.Reusable;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.base.Keys;
+import dagger.internal.codegen.base.MapType;
+import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.model.Scope;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Queue;
+import java.util.Set;
+import javax.inject.Inject;
+
+/** A factory for {@link BindingGraph} objects. */
+public final class LegacyBindingGraphFactory {
+
+  static boolean useLegacyBindingGraphFactory(
+      CompilerOptions compilerOptions, ComponentDescriptor componentDescriptor) {
+    return !compilerOptions.useBindingGraphFix();
+  }
+
+  static boolean hasStrictMultibindingsExemption(
+      CompilerOptions compilerOptions, ContributionBinding binding) {
+    // We only give the exemption to multibound map contributions.
+    if (!binding.contributionType().equals(ContributionType.MAP)) {
+      return false;
+    }
+    return !compilerOptions.strictMultibindingValidation();
+  }
+
+  private final InjectBindingRegistry injectBindingRegistry;
+  private final KeyFactory keyFactory;
+  private final BindingFactory bindingFactory;
+  private final BindingNode.Factory bindingNodeFactory;
+  private final ComponentDeclarations.Factory componentDeclarationsFactory;
+  private final LegacyBindingGraphConverter legacyBindingGraphConverter;
+  private final CompilerOptions compilerOptions;
+
+  @Inject
+  LegacyBindingGraphFactory(
+      InjectBindingRegistry injectBindingRegistry,
+      KeyFactory keyFactory,
+      BindingFactory bindingFactory,
+      BindingNode.Factory bindingNodeFactory,
+      ComponentDeclarations.Factory componentDeclarationsFactory,
+      LegacyBindingGraphConverter legacyBindingGraphConverter,
+      CompilerOptions compilerOptions) {
+    this.injectBindingRegistry = injectBindingRegistry;
+    this.keyFactory = keyFactory;
+    this.bindingFactory = bindingFactory;
+    this.bindingNodeFactory = bindingNodeFactory;
+    this.componentDeclarationsFactory = componentDeclarationsFactory;
+    this.legacyBindingGraphConverter = legacyBindingGraphConverter;
+    this.compilerOptions = compilerOptions;
+  }
+
+  /**
+   * Creates a binding graph for a component.
+   *
+   * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings;
+   *     otherwise it will include only bindings reachable from at least one entry point
+   */
+  public BindingGraph create(
+      ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
+    return legacyBindingGraphConverter.convert(
+        createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph),
+        createFullBindingGraph);
+  }
+
+  private LegacyBindingGraph createLegacyBindingGraph(
+      Optional<Resolver> parentResolver,
+      ComponentDescriptor componentDescriptor,
+      boolean createFullBindingGraph) {
+    Resolver requestResolver = new Resolver(parentResolver, componentDescriptor);
+
+    componentDescriptor.entryPointMethods().stream()
+        .map(method -> method.dependencyRequest().get())
+        .forEach(
+            entryPoint -> {
+              if (entryPoint.kind().equals(MEMBERS_INJECTION)) {
+                requestResolver.resolveMembersInjection(entryPoint.key());
+              } else {
+                requestResolver.resolve(entryPoint.key());
+              }
+            });
+
+    if (createFullBindingGraph) {
+      // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
+      // identifier so that the multibinding itself is resolved.
+      requestResolver.declarations.allDeclarations().stream()
+          // TODO(b/349155899): Consider resolving all declarations in full binding graph mode, not
+          //   just those from modules.
+          .filter(declaration -> declaration.contributingModule().isPresent())
+          .map(Declaration::key)
+          .map(Key::withoutMultibindingContributionIdentifier)
+          .forEach(requestResolver::resolve);
+    }
+
+    // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
+    // been detected during binding resolution. If a binding for a subcomponent is never resolved,
+    // no BindingGraph will be created for it and no implementation will be generated. This is
+    // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
+    // from a parent graph. This is done until no more new subcomponents are resolved.
+    Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
+    ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder();
+    for (ComponentDescriptor subcomponent :
+        Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) {
+      if (resolvedSubcomponents.add(subcomponent)) {
+        subgraphs.add(
+            createLegacyBindingGraph(
+                Optional.of(requestResolver), subcomponent, createFullBindingGraph));
+      }
+    }
+
+    return new LegacyBindingGraph(requestResolver, subgraphs.build());
+  }
+
+  /** Represents a fully resolved binding graph. */
+  static final class LegacyBindingGraph {
+    private final Resolver resolver;
+    private final ImmutableList<LegacyBindingGraph> resolvedSubgraphs;
+    private final ComponentNode componentNode;
+
+    LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs) {
+      this.resolver = resolver;
+      this.resolvedSubgraphs = resolvedSubgraphs;
+      this.componentNode =
+          ComponentNodeImpl.create(resolver.componentPath, resolver.componentDescriptor);
+    }
+
+    /** Returns the {@link ComponentNode} associated with this binding graph. */
+    public ComponentNode componentNode() {
+      return componentNode;
+    }
+
+    /** Returns the {@link ComponentPath} associated with this binding graph. */
+    public ComponentPath componentPath() {
+      return resolver.componentPath;
+    }
+
+    /** Returns the {@link ComponentDescriptor} associated with this binding graph. */
+    public ComponentDescriptor componentDescriptor() {
+      return resolver.componentDescriptor;
+    }
+
+    /**
+     * Returns the {@link LegacyResolvedBindings} in this graph or a parent graph that matches the
+     * given request.
+     *
+     * <p>An exception is thrown if there are no resolved bindings found for the request; however,
+     * this should never happen since all dependencies should have been resolved at this point.
+     */
+    public LegacyResolvedBindings resolvedBindings(BindingRequest request) {
+      return request.isRequestKind(RequestKind.MEMBERS_INJECTION)
+          ? resolver.getResolvedMembersInjectionBindings(request.key())
+          : resolver.getResolvedContributionBindings(request.key());
+    }
+
+    /**
+     * Returns all {@link LegacyResolvedBindings} for the given request.
+     *
+     * <p>Note that this only returns the bindings resolved in this component. Bindings resolved in
+     * parent components are not included.
+     */
+    public Iterable<LegacyResolvedBindings> resolvedBindings() {
+      // Don't return an immutable collection - this is only ever used for looping over all bindings
+      // in the graph. Copying is wasteful, especially if is a hashing collection, since the values
+      // should all, by definition, be distinct.
+      return Iterables.concat(
+          resolver.resolvedMembersInjectionBindings.values(),
+          resolver.resolvedContributionBindings.values());
+    }
+
+    /** Returns the resolved subgraphs. */
+    public ImmutableList<LegacyBindingGraph> subgraphs() {
+      return resolvedSubgraphs;
+    }
+  }
+
+  /**
+   * The collection of bindings that have been resolved for a key. For valid graphs, contains
+   * exactly one binding.
+   *
+   * <p>Separate {@link LegacyResolvedBindings} instances should be used if a {@link
+   * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same
+   * component. (This will only happen if a type has an {@code @Inject} constructor and members, the
+   * component has a members injection method, and the type is also requested normally.)
+   */
+  @AutoValue
+  abstract static class LegacyResolvedBindings {
+    /**
+     * Creates a {@link LegacyResolvedBindings} appropriate for when there are no bindings for a
+     * key.
+     */
+    static LegacyResolvedBindings create(Key key) {
+      return create(key, ImmutableSet.of());
+    }
+
+    /** Creates a {@link LegacyResolvedBindings} for a single binding. */
+    static LegacyResolvedBindings create(Key key, BindingNode bindingNode) {
+      return create(key, ImmutableSet.of(bindingNode));
+    }
+
+    /** Creates a {@link LegacyResolvedBindings} for multiple bindings. */
+    static LegacyResolvedBindings create(Key key, ImmutableSet<BindingNode> bindingNodes) {
+      return new AutoValue_LegacyBindingGraphFactory_LegacyResolvedBindings(key, bindingNodes);
+    }
+
+    /** The binding key for which the {@link #bindings()} have been resolved. */
+    abstract Key key();
+
+    /** All binding nodes for {@link #key()}, regardless of which component owns them. */
+    abstract ImmutableSet<BindingNode> bindingNodes();
+
+    // Computing the hash code is an expensive operation.
+    @Memoized
+    @Override
+    public abstract int hashCode();
+
+    // Suppresses ErrorProne warning that hashCode was overridden w/o equals
+    @Override
+    public abstract boolean equals(Object other);
+
+    /** All bindings for {@link #key()}, regardless of which component owns them. */
+    final ImmutableSet<Binding> bindings() {
+      return bindingNodes().stream()
+          .map(BindingNode::delegate)
+          .collect(toImmutableSet());
+    }
+
+    /** Returns {@code true} if there are no {@link #bindings()}. */
+    final boolean isEmpty() {
+      return bindingNodes().isEmpty();
+    }
+
+    /** All bindings for {@link #key()} that are owned by a component. */
+    ImmutableSet<BindingNode> bindingNodesOwnedBy(ComponentPath componentPath) {
+      return bindingNodes().stream()
+          .filter(bindingNode -> bindingNode.componentPath().equals(componentPath))
+          .collect(toImmutableSet());
+    }
+
+    /** Returns the binding node representing the given binding, or throws ISE if none exist. */
+    final BindingNode forBinding(Binding binding) {
+      return bindingNodes().stream()
+          .filter(bindingNode -> bindingNode.delegate().equals(binding))
+          .collect(onlyElement());
+    }
+  }
+
+  private final class Resolver {
+    final ComponentPath componentPath;
+    final Optional<Resolver> parentResolver;
+    final ComponentDescriptor componentDescriptor;
+    final ComponentDeclarations declarations;
+    final Map<Key, LegacyResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>();
+    final Map<Key, LegacyResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>();
+    final Deque<Key> cycleStack = new ArrayDeque<>();
+    final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>();
+    final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>();
+    final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>();
+
+    Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
+      this.parentResolver = parentResolver;
+      this.componentDescriptor = checkNotNull(componentDescriptor);
+      DaggerTypeElement componentType = DaggerTypeElement.from(componentDescriptor.typeElement());
+      componentPath =
+          parentResolver.isPresent()
+              ? parentResolver.get().componentPath.childPath(componentType)
+              : ComponentPath.create(ImmutableList.of(componentType));
+      declarations =
+          componentDeclarationsFactory.create(
+              parentResolver.map(parent -> parent.componentDescriptor),
+              componentDescriptor);
+      subcomponentsToResolve.addAll(
+          componentDescriptor.childComponentsDeclaredByFactoryMethods().values());
+      subcomponentsToResolve.addAll(
+          componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values());
+    }
+
+    /**
+     * Returns the resolved contribution bindings for the given {@link Key}:
+     *
+     * <ul>
+     *   <li>All explicit bindings for:
+     *       <ul>
+     *         <li>the requested key
+     *         <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>}
+     *         <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K,
+     *             Producer<V>>}.
+     *       </ul>
+     *   <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and
+     *       there are no explicit bindings or synthetic bindings.
+     * </ul>
+     */
+    LegacyResolvedBindings lookUpBindings(Key requestKey) {
+      Set<ContributionBinding> bindings = new LinkedHashSet<>();
+      Set<ContributionBinding> multibindingContributions = new LinkedHashSet<>();
+      Set<MultibindingDeclaration> multibindingDeclarations = new LinkedHashSet<>();
+      Set<OptionalBindingDeclaration> optionalBindingDeclarations = new LinkedHashSet<>();
+      Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>();
+
+      // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions.
+      for (Resolver resolver : getResolverLineage()) {
+        bindings.addAll(resolver.getLocalExplicitBindings(requestKey));
+        multibindingContributions.addAll(resolver.getLocalMultibindingContributions(requestKey));
+        multibindingDeclarations.addAll(resolver.declarations.multibindings(requestKey));
+        subcomponentDeclarations.addAll(resolver.declarations.subcomponents(requestKey));
+        // The optional binding declarations are keyed by the unwrapped type.
+        keyFactory.unwrapOptional(requestKey)
+            .map(resolver.declarations::optionalBindings)
+            .ifPresent(optionalBindingDeclarations::addAll);
+      }
+
+      // Add synthetic multibinding
+      if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) {
+        if (MapType.isMap(requestKey)) {
+          bindings.add(bindingFactory.multiboundMap(requestKey, multibindingContributions));
+        } else if (SetType.isSet(requestKey)) {
+          bindings.add(bindingFactory.multiboundSet(requestKey, multibindingContributions));
+        } else {
+          throw new AssertionError("Unexpected type in multibinding key: " + requestKey);
+        }
+      }
+
+      // Add synthetic optional binding
+      if (!optionalBindingDeclarations.isEmpty()) {
+        ImmutableSet<Binding> optionalContributions =
+            lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings();
+        bindings.add(
+            optionalContributions.isEmpty()
+                ? bindingFactory.syntheticAbsentOptionalDeclaration(requestKey)
+                : bindingFactory.syntheticPresentOptionalDeclaration(
+                    requestKey, optionalContributions));
+      }
+
+      // Add subcomponent creator binding
+      if (!subcomponentDeclarations.isEmpty()) {
+        ContributionBinding binding =
+            bindingFactory.subcomponentCreatorBinding(
+                ImmutableSet.copyOf(subcomponentDeclarations));
+        bindings.add(binding);
+        addSubcomponentToOwningResolver(binding);
+      }
+
+      // Add members injector binding
+      if (isTypeOf(requestKey.type().xprocessing(), TypeNames.MEMBERS_INJECTOR)) {
+        injectBindingRegistry.getOrFindMembersInjectorBinding(requestKey).ifPresent(bindings::add);
+      }
+
+      // Add Assisted Factory binding
+      if (isDeclared(requestKey.type().xprocessing())
+          && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) {
+        bindings.add(
+            bindingFactory.assistedFactoryBinding(
+                requestKey.type().xprocessing().getTypeElement(),
+                Optional.of(requestKey.type().xprocessing())));
+      }
+
+      // If there are no bindings, add the implicit @Inject-constructed binding if there is one.
+      if (bindings.isEmpty()) {
+        injectBindingRegistry
+            .getOrFindInjectionBinding(requestKey)
+            .filter(this::isCorrectlyScopedInSubcomponent)
+            .ifPresent(bindings::add);
+      }
+
+      return LegacyResolvedBindings.create(
+          requestKey,
+          bindings.stream()
+              .map(
+                  binding -> {
+                    Optional<BindingNode> bindingNodeOwnedByAncestor =
+                        getBindingNodeOwnedByAncestor(requestKey, binding);
+                    // If a binding is owned by an ancestor we use the corresponding BindingNode
+                    // instance directly rather than creating a new instance to avoid accidentally
+                    // including additional multi/optional/subcomponent declarations that don't
+                    // exist in the ancestor's BindingNode instance.
+                    return bindingNodeOwnedByAncestor.isPresent()
+                          ? bindingNodeOwnedByAncestor.get()
+                          : bindingNodeFactory.forContributionBindings(
+                              componentPath,
+                              binding,
+                              multibindingDeclarations,
+                              optionalBindingDeclarations,
+                              subcomponentDeclarations);
+                  })
+              .collect(toImmutableSet()));
+    }
+
+    /**
+     * Returns true if this binding graph resolution is for a subcomponent and the {@code @Inject}
+     * binding's scope correctly matches one of the components in the current component ancestry.
+     * If not, it means the binding is not owned by any of the currently known components, and will
+     * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped
+     * binding error at the root component).
+     */
+    private boolean isCorrectlyScopedInSubcomponent(ContributionBinding binding) {
+      checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION);
+      if (!rootComponent().isSubcomponent()
+          || !binding.scope().isPresent()
+          || binding.scope().get().isReusable()) {
+        return true;
+      }
+
+      Resolver owningResolver = getOwningResolver(binding).orElse(this);
+      ComponentDescriptor owningComponent = owningResolver.componentDescriptor;
+      return owningComponent.scopes().contains(binding.scope().get());
+    }
+
+    private ComponentDescriptor rootComponent() {
+      return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor);
+    }
+
+    /** Returns the resolved members injection bindings for the given {@link Key}. */
+    LegacyResolvedBindings lookUpMembersInjectionBinding(Key requestKey) {
+      // no explicit deps for members injection, so just look it up
+      Optional<MembersInjectionBinding> binding =
+          injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey);
+      return binding.isPresent()
+          ? LegacyResolvedBindings.create(
+              requestKey,
+              bindingNodeFactory.forMembersInjectionBinding(componentPath, binding.get()))
+          : LegacyResolvedBindings.create(requestKey);
+    }
+
+    /**
+     * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link
+     * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue
+     * will be used to detect which subcomponents need to be resolved.
+     */
+    private void addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding) {
+      checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
+      Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
+
+      XTypeElement builderType =
+          subcomponentCreatorBinding.key().type().xprocessing().getTypeElement();
+      owningResolver.subcomponentsToResolve.add(
+          owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
+    }
+
+    private ImmutableSet<ContributionBinding> createDelegateBindings(
+        ImmutableSet<DelegateDeclaration> delegateDeclarations) {
+      ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
+      for (DelegateDeclaration delegateDeclaration : delegateDeclarations) {
+        builder.add(createDelegateBinding(delegateDeclaration));
+      }
+      return builder.build();
+    }
+
+    /**
+     * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved
+     * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate
+     * bindings for the dependency key, there should still be only one binding for the delegate key.
+     */
+    private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) {
+      Key delegateKey = delegateDeclaration.delegateRequest().key();
+      if (cycleStack.contains(delegateKey)) {
+        return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
+      }
+
+      LegacyResolvedBindings resolvedDelegate;
+      try {
+        cycleStack.push(delegateKey);
+        resolvedDelegate = lookUpBindings(delegateKey);
+      } finally {
+        cycleStack.pop();
+      }
+      if (resolvedDelegate.bindings().isEmpty()) {
+        // This is guaranteed to result in a missing binding error, so it doesn't matter if the
+        // binding is a Provision or Production, except if it is a @IntoMap method, in which
+        // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a
+        // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a
+        // strange error, that the RHS needs to be provided with an @Inject or @Provides
+        // annotated method, but a user should be able to figure out if a @Produces annotation
+        // is needed.
+        // TODO(gak): revisit how we model missing delegates if/when we clean up how we model
+        // binding declarations
+        return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
+      }
+      // It doesn't matter which of these is selected, since they will later on produce a
+      // duplicate binding error.
+      ContributionBinding explicitDelegate =
+          (ContributionBinding) resolvedDelegate.bindings().iterator().next();
+      return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate);
+    }
+
+    /**
+     * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component,
+     * if one exists. Otherwise returns {@link Optional#empty()}.
+     */
+    private Optional<BindingNode> getBindingNodeOwnedByAncestor(
+        Key requestKey, ContributionBinding binding) {
+      if (canBeResolvedInParent(requestKey, binding)) {
+        // Resolve in the parent to make sure we have the most recent multi/optional contributions.
+        parentResolver.get().resolve(requestKey);
+        if (!requiresResolution(binding)) {
+          return Optional.of(getPreviouslyResolvedBindings(requestKey).get().forBinding(binding));
+        }
+      }
+      return Optional.empty();
+    }
+
+    private boolean canBeResolvedInParent(Key requestKey, ContributionBinding binding) {
+      if (parentResolver.isEmpty()) {
+        return false;
+      }
+      Optional<Resolver> owningResolver = getOwningResolver(binding);
+      if (owningResolver.isPresent()) {
+        return !owningResolver.get().equals(this);
+      }
+      return !Keys.isComponentOrCreator(requestKey)
+          // TODO(b/305748522): Allow caching for assisted injection bindings.
+          && binding.kind() != BindingKind.ASSISTED_INJECTION
+          && getPreviouslyResolvedBindings(requestKey).isPresent()
+          && getPreviouslyResolvedBindings(requestKey).get().bindings().contains(binding);
+    }
+
+    private Optional<Resolver> getOwningResolver(ContributionBinding binding) {
+      // TODO(ronshapiro): extract the different pieces of this method into their own methods
+      if ((binding.scope().isPresent() && binding.scope().get().isProductionScope())
+          || binding.kind().equals(BindingKind.PRODUCTION)) {
+        for (Resolver requestResolver : getResolverLineage()) {
+          // Resolve @Inject @ProductionScope bindings at the highest production component.
+          if (binding.kind().equals(INJECTION)
+              && requestResolver.componentDescriptor.isProduction()) {
+            return Optional.of(requestResolver);
+          }
+
+          // Resolve explicit @Produces and @ProductionScope bindings at the highest component that
+          // installs the binding.
+          if (requestResolver.containsExplicitBinding(binding)) {
+            return Optional.of(requestResolver);
+          }
+        }
+      }
+
+      if (binding.scope().isPresent() && binding.scope().get().isReusable()) {
+        for (Resolver requestResolver : getResolverLineage().reverse()) {
+          // If a @Reusable binding was resolved in an ancestor, use that component.
+          LegacyResolvedBindings resolvedBindings =
+              requestResolver.resolvedContributionBindings.get(binding.key());
+          if (resolvedBindings != null && resolvedBindings.bindings().contains(binding)) {
+            return Optional.of(requestResolver);
+          }
+        }
+        // If a @Reusable binding was not resolved in any ancestor, resolve it here.
+        return Optional.empty();
+      }
+
+      // TODO(b/359893922): we currently iterate from child to parent to find an owning resolver,
+      // but we probably want to iterate from parent to child to catch missing bindings in
+      // misconfigured repeated modules.
+      for (Resolver requestResolver : getResolverLineage().reverse()) {
+        if (requestResolver.containsExplicitBinding(binding)) {
+          return Optional.of(requestResolver);
+        }
+      }
+
+      // look for scope separately.  we do this for the case where @Singleton can appear twice
+      // in the † compatibility mode
+      Optional<Scope> bindingScope = binding.scope();
+      if (bindingScope.isPresent()) {
+        for (Resolver requestResolver : getResolverLineage().reverse()) {
+          if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) {
+            return Optional.of(requestResolver);
+          }
+        }
+      }
+      return Optional.empty();
+    }
+
+    private boolean containsExplicitBinding(ContributionBinding binding) {
+      return declarations.bindings(binding.key()).contains(binding)
+          || resolverContainsDelegateDeclarationForBinding(binding)
+          || !declarations.subcomponents(binding.key()).isEmpty();
+    }
+
+    /** Returns true if {@code binding} was installed in a module in this resolver's component. */
+    private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) {
+      if (!binding.kind().equals(DELEGATE)) {
+        return false;
+      }
+      if (hasStrictMultibindingsExemption(compilerOptions, binding)) {
+        return false;
+      }
+      return declarations.delegates(binding.key()).stream()
+          .anyMatch(
+              declaration ->
+                  declaration.contributingModule().equals(binding.contributingModule())
+                  && declaration.bindingElement().equals(binding.bindingElement()));
+    }
+
+    /** Returns the resolver lineage from parent to child. */
+    private ImmutableList<Resolver> getResolverLineage() {
+      ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder();
+      for (Optional<Resolver> currentResolver = Optional.of(this);
+          currentResolver.isPresent();
+          currentResolver = currentResolver.get().parentResolver) {
+        resolverList.add(currentResolver.get());
+      }
+      return resolverList.build().reverse();
+    }
+
+    /**
+     * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this
+     * resolver.
+     */
+    private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) {
+      return ImmutableSet.<ContributionBinding>builder()
+          .addAll(declarations.bindings(key))
+          .addAll(createDelegateBindings(declarations.delegates(key)))
+          .build();
+    }
+
+    /**
+     * Returns the explicit multibinding contributions that contribute to the map or set requested
+     * by {@code key} from this resolver.
+     */
+    private ImmutableSet<ContributionBinding> getLocalMultibindingContributions(Key key) {
+      return ImmutableSet.<ContributionBinding>builder()
+          .addAll(declarations.multibindingContributions(key))
+          .addAll(createDelegateBindings(declarations.delegateMultibindingContributions(key)))
+          .build();
+    }
+
+    /**
+     * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all
+     * ancestor resolvers.
+     */
+    private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) {
+      Optional<Key> unwrapped = keyFactory.unwrapOptional(key);
+      if (unwrapped.isEmpty()) {
+        return ImmutableSet.of();
+      }
+      ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder();
+      for (Resolver resolver : getResolverLineage()) {
+        declarations.addAll(resolver.declarations.optionalBindings(unwrapped.get()));
+      }
+      return declarations.build();
+    }
+
+    /**
+     * Returns the {@link LegacyResolvedBindings} for {@code key} that was resolved in this resolver
+     * or an ancestor resolver. Only checks for {@link ContributionBinding}s as {@link
+     * MembersInjectionBinding}s are not inherited.
+     */
+    private Optional<LegacyResolvedBindings> getPreviouslyResolvedBindings(Key key) {
+      Optional<LegacyResolvedBindings> result =
+          Optional.ofNullable(resolvedContributionBindings.get(key));
+      if (result.isPresent()) {
+        return result;
+      } else if (parentResolver.isPresent()) {
+        return parentResolver.get().getPreviouslyResolvedBindings(key);
+      } else {
+        return Optional.empty();
+      }
+    }
+
+    private void resolveMembersInjection(Key key) {
+      LegacyResolvedBindings bindings = lookUpMembersInjectionBinding(key);
+      resolveDependencies(bindings);
+      resolvedMembersInjectionBindings.put(key, bindings);
+    }
+
+    void resolve(Key key) {
+      // If we find a cycle, stop resolving. The original request will add it with all of the
+      // other resolved deps.
+      if (cycleStack.contains(key)) {
+        return;
+      }
+
+      // If the binding was previously resolved in this (sub)component, don't resolve it again.
+      if (resolvedContributionBindings.containsKey(key)) {
+        return;
+      }
+
+      cycleStack.push(key);
+      try {
+        LegacyResolvedBindings bindings = lookUpBindings(key);
+        resolvedContributionBindings.put(key, bindings);
+        resolveDependencies(bindings);
+      } finally {
+        cycleStack.pop();
+      }
+    }
+
+    /**
+     * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this
+     * component.
+     */
+    private void resolveDependencies(LegacyResolvedBindings resolvedBindings) {
+      for (BindingNode binding : resolvedBindings.bindingNodesOwnedBy(componentPath)) {
+        for (DependencyRequest dependency : binding.dependencies()) {
+          resolve(dependency.key());
+        }
+      }
+    }
+
+    private LegacyResolvedBindings getResolvedContributionBindings(Key key) {
+      if (resolvedContributionBindings.containsKey(key)) {
+        return resolvedContributionBindings.get(key);
+      }
+      if (parentResolver.isPresent()) {
+        return parentResolver.get().getResolvedContributionBindings(key);
+      }
+      throw new AssertionError("No resolved bindings for key: " + key);
+    }
+
+    private LegacyResolvedBindings getResolvedMembersInjectionBindings(Key key) {
+      return resolvedMembersInjectionBindings.get(key);
+    }
+
+    private boolean requiresResolution(Binding binding) {
+      return new RequiresResolutionChecker().requiresResolution(binding);
+    }
+
+    private final class RequiresResolutionChecker {
+      private final Set<Object> cycleChecker = new HashSet<>();
+
+      /**
+       * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with
+       * contributions declared within this component's modules or optional bindings with present
+       * values declared within this component's modules, or if any of its unscoped dependencies
+       * depend on such bindings.
+       *
+       * <p>We don't care about scoped dependencies because they will never depend on bindings from
+       * subcomponents.
+       *
+       * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty
+       */
+      private boolean requiresResolution(Key key) {
+        // Don't recur infinitely if there are valid cycles in the dependency graph.
+        // http://b/23032377
+        if (!cycleChecker.add(key)) {
+          return false;
+        }
+        return reentrantComputeIfAbsent(
+            keyDependsOnLocalBindingsCache, key, this::requiresResolutionUncached);
+      }
+
+      /**
+       * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable}
+       * scope) and depends on multibindings with contributions declared within this component's
+       * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend
+       * on such local multibindings.
+       *
+       * <p>We don't care about non-reusable scoped dependencies because they will never depend on
+       * multibindings with contributions from subcomponents.
+       */
+      private boolean requiresResolution(Binding binding) {
+        if (!cycleChecker.add(binding)) {
+          return false;
+        }
+        return reentrantComputeIfAbsent(
+            bindingDependsOnLocalBindingsCache, binding, this::requiresResolutionUncached);
+      }
+
+      private boolean requiresResolutionUncached(Key key) {
+        checkArgument(
+            getPreviouslyResolvedBindings(key).isPresent(),
+            "no previously resolved bindings in %s for %s",
+            Resolver.this,
+            key);
+        LegacyResolvedBindings previouslyResolvedBindings =
+            getPreviouslyResolvedBindings(key).get();
+        if (hasLocalBindings(previouslyResolvedBindings)) {
+          return true;
+        }
+
+        for (Binding binding : previouslyResolvedBindings.bindings()) {
+          if (requiresResolution(binding)) {
+            return true;
+          }
+        }
+        return false;
+      }
+
+      private boolean requiresResolutionUncached(Binding binding) {
+        if ((!binding.scope().isPresent() || binding.scope().get().isReusable())
+            // TODO(beder): Figure out what happens with production subcomponents.
+            && !binding.kind().equals(BindingKind.PRODUCTION)) {
+          for (DependencyRequest dependency : binding.dependencies()) {
+            if (requiresResolution(dependency.key())) {
+              return true;
+            }
+          }
+        }
+        return false;
+      }
+    }
+
+    private boolean hasLocalBindings(LegacyResolvedBindings resolvedBindings) {
+      return hasLocalMultibindingContributions(resolvedBindings.key())
+          || hasLocalOptionalBindingContribution(resolvedBindings);
+    }
+
+    /**
+     * Returns {@code true} if there is at least one multibinding contribution declared within
+     * this component's modules that matches the key.
+     */
+    private boolean hasLocalMultibindingContributions(Key requestKey) {
+      return !declarations.multibindingContributions(requestKey).isEmpty()
+          || !declarations.delegateMultibindingContributions(requestKey).isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if there is a contribution in this component for an {@code
+     * Optional<Foo>} key that has not been contributed in a parent.
+     */
+    private boolean hasLocalOptionalBindingContribution(LegacyResolvedBindings resolvedBindings) {
+      return hasLocalOptionalBindingContribution(
+          resolvedBindings.key(), resolvedBindings.bindings());
+    }
+
+    private boolean hasLocalOptionalBindingContribution(
+          Key key, ImmutableSet<? extends Binding> previouslyResolvedBindings) {
+      if (previouslyResolvedBindings.stream()
+          .map(Binding::kind)
+          .anyMatch(isEqual(OPTIONAL))) {
+        return hasLocalExplicitBindings(keyFactory.unwrapOptional(key).get());
+      } else {
+        // If a parent contributes a @Provides Optional<Foo> binding and a child has a
+        // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for
+        // Foo on its own
+        return !getOptionalBindingDeclarations(key).isEmpty();
+      }
+    }
+
+    /**
+     * Returns {@code true} if there is at least one explicit binding that matches the given key.
+     */
+    private boolean hasLocalExplicitBindings(Key requestKey) {
+      return !declarations.bindings(requestKey).isEmpty()
+          || !declarations.delegates(requestKey).isEmpty();
+    }
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/MapKeys.java b/java/dagger/internal/codegen/binding/MapKeys.java
index 61ef9f2..a38bf8a 100644
--- a/java/dagger/internal/codegen/binding/MapKeys.java
+++ b/java/dagger/internal/codegen/binding/MapKeys.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.binding;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static androidx.room.compiler.processing.XTypeKt.isArray;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Iterables.getOnlyElement;
@@ -46,13 +47,14 @@
 import dagger.internal.codegen.base.DaggerSuperficialValidation;
 import dagger.internal.codegen.base.MapKeyAccessibility;
 import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.xprocessing.XElements;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 
 /** Methods for extracting {@link MapKey} annotations and key code blocks from binding elements. */
 public final class MapKeys {
+  public static final String LAZY_CLASS_KEY_NAME_FIELD = "lazyClassKeyName";
+  public static final String KEEP_FIELD_TYPE_FIELD = "keepFieldType";
 
   /**
    * If {@code bindingElement} is annotated with a {@link MapKey} annotation, returns it.
@@ -134,7 +136,7 @@
    */
   public static CodeBlock getMapKeyExpression(
       ContributionBinding binding, ClassName requestingClass, XProcessingEnv processingEnv) {
-    XAnnotation mapKeyAnnotation = binding.mapKey().get().xprocessing();
+    XAnnotation mapKeyAnnotation = binding.mapKey().get();
     return MapKeyAccessibility.isMapKeyAccessibleFrom(
             mapKeyAnnotation, requestingClass.packageName())
         ? directMapKeyExpression(mapKeyAnnotation, processingEnv)
@@ -176,7 +178,8 @@
    * XProcessingEnv)} is generated.
    */
   public static ClassName mapKeyProxyClassName(ContributionBinding binding) {
-    return elementBasedClassName(asExecutable(binding.bindingElement().get()), "MapKey");
+    return toJavaPoet(
+        elementBasedClassName(asExecutable(binding.bindingElement().get()), "MapKey"));
   }
 
   /**
@@ -188,7 +191,6 @@
       ContributionBinding binding, XProcessingEnv processingEnv) {
     return binding
         .mapKey()
-        .map(DaggerAnnotation::xprocessing)
         .filter(mapKey -> !isMapKeyPubliclyAccessible(mapKey))
         .map(
             mapKey ->
@@ -213,12 +215,21 @@
           && contributionBinding
               .mapKey()
               .get()
-              .xprocessing()
               .getClassName()
               .equals(TypeNames.LAZY_CLASS_KEY);
     }
     return false;
   }
 
+  public static CodeBlock getLazyClassMapKeyExpression(ContributionBinding contributionBinding) {
+    ClassName proxyClassName =
+        lazyClassKeyProxyClassName(XElements.asMethod(contributionBinding.bindingElement().get()));
+    return CodeBlock.of("$T.$N", proxyClassName, LAZY_CLASS_KEY_NAME_FIELD);
+  }
+
+  public static ClassName lazyClassKeyProxyClassName(XMethodElement methodElement) {
+    return toJavaPoet(elementBasedClassName(methodElement, "_LazyMapKey"));
+  }
+
   private MapKeys() {}
 }
diff --git a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
index b546f6a..17580ee 100644
--- a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
+++ b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
@@ -17,10 +17,11 @@
 package dagger.internal.codegen.binding;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 import static dagger.internal.codegen.xprocessing.XElements.isPrivate;
-import static java.util.stream.Collectors.toList;
 
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XFieldElement;
@@ -33,19 +34,12 @@
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
 import java.util.Optional;
 
-/** Represents the full members injection of a particular type. */
+/** A binding for a {@link BindingKind#MEMBERS_INJECTION}. */
 @AutoValue
 public abstract class MembersInjectionBinding extends Binding {
-  static MembersInjectionBinding create(
-      Key key,
-      ImmutableSet<DependencyRequest> dependencies,
-      Optional<MembersInjectionBinding> unresolved,
-      ImmutableSortedSet<InjectionSite> injectionSites) {
-    return new AutoValue_MembersInjectionBinding(key, dependencies, unresolved, injectionSites);
-  }
-
   @Override
   public final Optional<XElement> bindingElement() {
     return Optional.of(membersInjectedType());
@@ -56,9 +50,6 @@
   }
 
   @Override
-  public abstract Optional<MembersInjectionBinding> unresolved();
-
-  @Override
   public Optional<XTypeElement> contributingModule() {
     return Optional.empty();
   }
@@ -67,8 +58,8 @@
   public abstract ImmutableSortedSet<InjectionSite> injectionSites();
 
   @Override
-  public BindingType bindingType() {
-    return BindingType.MEMBERS_INJECTION;
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.MEMBERS_INJECTION);
   }
 
   @Override
@@ -81,6 +72,13 @@
     return false;
   }
 
+  @Override
+  public final ImmutableSet<DependencyRequest> dependencies() {
+    return injectionSites().stream()
+        .flatMap(injectionSite -> injectionSite.dependencies().stream())
+        .collect(toImmutableSet());
+  }
+
   /**
    * Returns {@code true} if any of this binding's injection sites are directly on the bound type.
    */
@@ -95,6 +93,11 @@
     return false;
   }
 
+  @Override
+  public Optional<Scope> scope() {
+    return Optional.empty();
+  }
+
   @Memoized
   @Override
   public abstract int hashCode();
@@ -103,6 +106,22 @@
   @Override
   public abstract boolean equals(Object obj);
 
+  static Builder builder() {
+    return new AutoValue_MembersInjectionBinding.Builder();
+  }
+
+  /** A {@link MembersInjectionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder {
+    abstract Builder key(Key key);
+
+    abstract Builder unresolved(Optional<? extends Binding> unresolved);
+
+    abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
+
+    abstract MembersInjectionBinding build();
+  }
+
   /** Metadata about a field or method injection site. */
   @AutoValue
   public abstract static class InjectionSite {
@@ -131,7 +150,7 @@
           .filter(InjectionAnnotations::hasInjectAnnotation)
           .filter(element -> !isPrivate(element))
           .filter(element -> getSimpleName(element).equals(getSimpleName(this.element())))
-          .collect(toList())
+          .collect(toImmutableList())
           .indexOf(element());
     }
 
diff --git a/java/dagger/internal/codegen/binding/MembersInjectorBinding.java b/java/dagger/internal/codegen/binding/MembersInjectorBinding.java
new file mode 100644
index 0000000..cd9a68d
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MembersInjectorBinding.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#MEMBERS_INJECTOR}. */
+@CheckReturnValue
+@AutoValue
+public abstract class MembersInjectorBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.MEMBERS_INJECTOR;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return injectionSites().stream()
+        .flatMap(i -> i.dependencies().stream())
+        .collect(toImmutableSet());
+  }
+
+  /** {@link InjectionSite}s for all {@code @Inject} members. */
+  public abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_MembersInjectorBinding.Builder();
+  }
+
+  /** A {@link MembersInjectorBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<MembersInjectorBinding, Builder> {
+    abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
index d7fea80..7738fe9 100644
--- a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
+++ b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
@@ -38,6 +38,7 @@
 import com.google.common.collect.Streams;
 import com.squareup.javapoet.ClassName;
 import dagger.internal.codegen.base.Formatter;
+import dagger.internal.codegen.xprocessing.Nullability;
 import dagger.internal.codegen.xprocessing.XAnnotations;
 import dagger.internal.codegen.xprocessing.XTypes;
 import java.util.Iterator;
diff --git a/java/dagger/internal/codegen/binding/MissingBindingImpl.java b/java/dagger/internal/codegen/binding/MissingBindingImpl.java
new file mode 100644
index 0000000..1d964e0
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MissingBindingImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import dagger.internal.codegen.model.BindingGraph.MissingBinding;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.Key;
+
+/** An implementation of {@link MissingBinding}. */
+@AutoValue
+abstract class MissingBindingImpl extends MissingBinding {
+  static MissingBinding create(ComponentPath component, Key key) {
+    return new AutoValue_MissingBindingImpl(component, key);
+  }
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  @Override
+  public abstract boolean equals(Object o);
+}
\ No newline at end of file
diff --git a/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
index 62cfa7f..bde718f 100644
--- a/java/dagger/internal/codegen/binding/ModuleDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
@@ -79,10 +79,13 @@
   /** The kind of the module. */
   public abstract ModuleKind kind();
 
+  /** Whether the module is implicitly included rather than directly referenced in annotation. */
+  public abstract boolean isImplicitlyIncluded();
+
   /** Returns all of the bindings declared in this module. */
   @Memoized
-  public ImmutableSet<BindingDeclaration> allBindingDeclarations() {
-    return ImmutableSet.<BindingDeclaration>builder()
+  public ImmutableSet<Declaration> allBindingDeclarations() {
+    return ImmutableSet.<Declaration>builder()
         .addAll(bindings())
         .addAll(delegateDeclarations())
         .addAll(multibindingDeclarations())
@@ -93,7 +96,7 @@
 
   /** Returns the keys of all bindings declared by this module. */
   ImmutableSet<Key> allBindingKeys() {
-    return allBindingDeclarations().stream().map(BindingDeclaration::key).collect(toImmutableSet());
+    return allBindingDeclarations().stream().map(Declaration::key).collect(toImmutableSet());
   }
 
   /** A {@link ModuleDescriptor} factory. */
@@ -107,6 +110,7 @@
     private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory;
     private final DaggerSuperficialValidation superficialValidation;
     private final Map<XTypeElement, ModuleDescriptor> cache = new HashMap<>();
+    private final Set<XTypeElement> implicitlyIncludedModules = new LinkedHashSet<>();
 
     @Inject
     Factory(
@@ -174,7 +178,8 @@
           subcomponentDeclarationFactory.forModule(moduleElement),
           delegates.build(),
           optionalDeclarations.build(),
-          ModuleKind.forAnnotatedElement(moduleElement).get());
+          ModuleKind.forAnnotatedElement(moduleElement).get(),
+          implicitlyIncludedModules.contains(moduleElement));
     }
 
     private void collectCompanionModuleBindings(
@@ -231,7 +236,10 @@
           .ifPresent(
               moduleAnnotation -> {
                 includedModules.addAll(moduleAnnotation.includes());
-                includedModules.addAll(implicitlyIncludedModules(moduleElement));
+                ImmutableSet<XTypeElement> daggerAndroidModules =
+                    implicitlyIncludedModules(moduleElement);
+                includedModules.addAll(daggerAndroidModules);
+                implicitlyIncludedModules.addAll(daggerAndroidModules);
               });
       return includedModules;
     }
@@ -259,7 +267,7 @@
           module.getPackageName(),
           String.format(
               "%s_%s",
-              classFileName(module.getClassName()),
+              classFileName(module.asClassName()),
               LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(method))));
     }
 
diff --git a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
index 54672fc..1cfded6 100644
--- a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
@@ -42,7 +42,7 @@
  * method annotated with {@link Multibinds @Multibinds}.
  */
 @AutoValue
-public abstract class MultibindingDeclaration extends BindingDeclaration
+public abstract class MultibindingDeclaration extends Declaration
     implements HasContributionType {
 
   /**
diff --git a/java/dagger/internal/codegen/binding/MultiboundMapBinding.java b/java/dagger/internal/codegen/binding/MultiboundMapBinding.java
new file mode 100644
index 0000000..0a8c971
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MultiboundMapBinding.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#MULTIBOUND_MAP}. */
+@CheckReturnValue
+@AutoValue
+public abstract class MultiboundMapBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.MULTIBOUND_MAP;
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_MultiboundMapBinding.Builder();
+  }
+
+  /** A {@link MultiboundMapBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<MultiboundMapBinding, Builder> {
+    abstract Builder dependencies(ImmutableSet<DependencyRequest> dependencies);
+
+    abstract Builder optionalBindingType(Optional<BindingType> optionalBindingType);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/MultiboundSetBinding.java b/java/dagger/internal/codegen/binding/MultiboundSetBinding.java
new file mode 100644
index 0000000..607ade8
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/MultiboundSetBinding.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#MULTIBOUND_SET}. */
+@CheckReturnValue
+@AutoValue
+public abstract class MultiboundSetBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.MULTIBOUND_SET;
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_MultiboundSetBinding.Builder();
+  }
+
+  /** A {@link MultiboundSetBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<MultiboundSetBinding, Builder> {
+    abstract Builder dependencies(ImmutableSet<DependencyRequest> dependencies);
+
+    abstract Builder optionalBindingType(Optional<BindingType> optionalBindingType);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/Nullability.java b/java/dagger/internal/codegen/binding/Nullability.java
deleted file mode 100644
index 4231a8f..0000000
--- a/java/dagger/internal/codegen/binding/Nullability.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2023 The Dagger 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
- *
- * 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 dagger.internal.codegen.binding;
-
-import static androidx.room.compiler.processing.XElementKt.isMethod;
-import static androidx.room.compiler.processing.XElementKt.isVariableElement;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.xprocessing.XElements.asMethod;
-import static dagger.internal.codegen.xprocessing.XElements.asVariable;
-
-import androidx.room.compiler.processing.XAnnotation;
-import androidx.room.compiler.processing.XElement;
-import androidx.room.compiler.processing.XNullability;
-import androidx.room.compiler.processing.XType;
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.xprocessing.XAnnotations;
-import java.util.stream.Stream;
-
-/**
- * Contains information about the nullability of an element.
- *
- * <p>Note that an element can be nullable if either:
- *
- * <ul>
- *   <li>The element is annotated with {@code Nullable} or
- *   <li>the associated kotlin type is nullable (i.e. {@code T?} types in Kotlin source).
- * </ul>
- */
-@AutoValue
-public abstract class Nullability {
-  /** A constant that can represent any non-null element. */
-  public static final Nullability NOT_NULLABLE =
-      new AutoValue_Nullability(false, ImmutableSet.of());
-
-  public static Nullability of(XElement element) {
-    return new AutoValue_Nullability(
-        /* isKotlinTypeNullable= */ isKotlinTypeNullable(element),
-        /* nullableAnnotations= */ getNullableAnnotations(element));
-  }
-
-  private static ImmutableSet<ClassName> getNullableAnnotations(XElement element) {
-    return getNullableAnnotations(element.getAllAnnotations().stream(), ImmutableSet.of());
-  }
-
-  private static ImmutableSet<ClassName> getNullableAnnotations(
-      Stream<XAnnotation> annotations,
-      ImmutableSet<ClassName> filterSet) {
-    return annotations
-        .map(XAnnotations::getClassName)
-        .filter(annotation -> annotation.simpleName().contentEquals("Nullable"))
-        .filter(annotation -> !filterSet.contains(annotation))
-        .collect(toImmutableSet());
-  }
-
-  /**
-   * Returns {@code true} if the element's type is a Kotlin nullable type, e.g. {@code Foo?}.
-   *
-   * <p>Note that this method ignores any {@code @Nullable} type annotations and only looks for
-   * explicit {@code ?} usages on kotlin types.
-   */
-  private static boolean isKotlinTypeNullable(XElement element) {
-    if (element.getClosestMemberContainer().isFromJava()) {
-      // Note: Technically, it isn't possible for Java sources to have nullable types like in Kotlin
-      // sources, but for some reason KSP treats certain types as nullable if they have a
-      // specific @Nullable (TYPE_USE target) annotation. Thus, to avoid inconsistencies with KAPT,
-      // just return false if this element is from a java source.
-      return false;
-    } else if (isMethod(element)) {
-      return isKotlinTypeNullable(asMethod(element).getReturnType());
-    } else if (isVariableElement(element)) {
-      return isKotlinTypeNullable(asVariable(element).getType());
-    } else {
-      return false;
-    }
-  }
-
-  private static boolean isKotlinTypeNullable(XType type) {
-    return type.getNullability() == XNullability.NULLABLE;
-  }
-
-  public abstract boolean isKotlinTypeNullable();
-
-  public abstract ImmutableSet<ClassName> nullableAnnotations();
-
-  public final boolean isNullable() {
-    return isKotlinTypeNullable() || !nullableAnnotations().isEmpty();
-  }
-
-  Nullability() {}
-}
diff --git a/java/dagger/internal/codegen/binding/OptionalBinding.java b/java/dagger/internal/codegen/binding/OptionalBinding.java
new file mode 100644
index 0000000..172db51
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/OptionalBinding.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#OPTIONAL}. */
+@CheckReturnValue
+@AutoValue
+public abstract class OptionalBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.OPTIONAL;
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return delegateRequest().isPresent()
+        ? ImmutableSet.of(delegateRequest().get())
+        : ImmutableSet.of();
+  }
+
+  /** Returns the delegate {@link DependencyRequest} if this represents a "present" optional. */
+  abstract Optional<DependencyRequest> delegateRequest();
+
+  @Override
+  public boolean requiresModuleInstance() {
+    return false;
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_OptionalBinding.Builder();
+  }
+
+  /** A {@link OptionalBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder extends ContributionBinding.Builder<OptionalBinding, Builder> {
+    abstract Builder delegateRequest(DependencyRequest delegateRequest);
+
+    abstract Builder optionalBindingType(Optional<BindingType> optionalBindingType);
+  }
+}
diff --git a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
index 60d56bb..ab183cc 100644
--- a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
@@ -30,7 +30,7 @@
 
 /** A {@link BindsOptionalOf} declaration. */
 @AutoValue
-abstract class OptionalBindingDeclaration extends BindingDeclaration {
+abstract class OptionalBindingDeclaration extends Declaration {
 
   /**
    * {@inheritDoc}
diff --git a/java/dagger/internal/codegen/binding/ProductionBinding.java b/java/dagger/internal/codegen/binding/ProductionBinding.java
index 0bcf8e7..574a864 100644
--- a/java/dagger/internal/codegen/binding/ProductionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProductionBinding.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Dagger Authors.
+ * Copyright (C) 2024 The Dagger Authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,90 +16,56 @@
 
 package dagger.internal.codegen.binding;
 
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.javapoet.TypeNames.isFutureType;
-
-import androidx.room.compiler.processing.XMethodElement;
-import androidx.room.compiler.processing.XType;
 import com.google.auto.value.AutoValue;
 import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.errorprone.annotations.CheckReturnValue;
 import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.Optional;
-import java.util.stream.Stream;
 
-/** A value object representing the mechanism by which a {@link Key} can be produced. */
+/** A binding for a {@link BindingKind#PRODUCTION}. */
 @CheckReturnValue
 @AutoValue
 public abstract class ProductionBinding extends ContributionBinding {
-
   @Override
-  public BindingType bindingType() {
-    return BindingType.PRODUCTION;
+  public BindingKind kind() {
+    return BindingKind.PRODUCTION;
   }
 
   @Override
-  public abstract Optional<ProductionBinding> unresolved();
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PRODUCTION);
+  }
+  @Override
+  @Memoized
+  public ContributionType contributionType() {
+    return ContributionType.fromBindingElement(bindingElement().get());
+  }
 
   @Override
-  public ImmutableSet<DependencyRequest> implicitDependencies() {
-    return Stream.of(executorRequest(), monitorRequest())
-        .filter(Optional::isPresent)
-        .map(Optional::get)
-        .collect(toImmutableSet());
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
   }
 
-  /** What kind of object a {@code @Produces}-annotated method returns. */
-  public enum ProductionKind {
-    /** A value. */
-    IMMEDIATE,
-    /** A {@code ListenableFuture<T>}. */
-    FUTURE,
-    /** A {@code Set<ListenableFuture<T>>}. */
-    SET_OF_FUTURE;
+  /** Dependencies necessary to invoke the {@code @Produces} method. */
+  public abstract ImmutableSet<DependencyRequest> explicitDependencies();
 
-    /** Returns the kind of object a {@code @Produces}-annotated method returns. */
-    public static ProductionKind fromProducesMethod(XMethodElement producesMethod) {
-      if (isFutureType(producesMethod.getReturnType())) {
-        return FUTURE;
-      } else if (ContributionType.fromBindingElement(producesMethod)
-              .equals(ContributionType.SET_VALUES)
-          && isFutureType(SetType.from(producesMethod.getReturnType()).elementType())) {
-        return SET_OF_FUTURE;
-      } else {
-        return IMMEDIATE;
-      }
-    }
+  @Override
+  @Memoized
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.<DependencyRequest>builder()
+        .add(executorRequest())
+        .add(monitorRequest())
+        .addAll(explicitDependencies())
+        .build();
   }
 
-  /**
-   * Returns the kind of object the produces method returns. All production bindings from
-   * {@code @Produces} methods will have a production kind, but synthetic production bindings may
-   * not.
-   */
-  public abstract Optional<ProductionKind> productionKind();
+  public abstract DependencyRequest executorRequest();
 
-  /** Returns the list of types in the throws clause of the method. */
-  public abstract ImmutableList<XType> thrownTypes();
-
-  /**
-   * If this production requires an executor, this will be the corresponding request.  All
-   * production bindings from {@code @Produces} methods will have an executor request, but
-   * synthetic production bindings may not.
-   */
-  abstract Optional<DependencyRequest> executorRequest();
-
-  /** If this production requires a monitor, this will be the corresponding request.  All
-   * production bindings from {@code @Produces} methods will have a monitor request, but synthetic
-   * production bindings may not.
-   */
-  abstract Optional<DependencyRequest> monitorRequest();
+  public abstract DependencyRequest monitorRequest();
 
   // Profiling determined that this method is called enough times that memoizing it had a measurable
   // performance improvement for large components.
@@ -109,13 +75,6 @@
     return super.requiresModuleInstance();
   }
 
-  public static Builder builder() {
-    return new AutoValue_ProductionBinding.Builder()
-        .nullability(Nullability.NOT_NULLABLE)
-        .explicitDependencies(ImmutableList.<DependencyRequest>of())
-        .thrownTypes(ImmutableList.<XType>of());
-  }
-
   @Override
   public abstract Builder toBuilder();
 
@@ -127,28 +86,17 @@
   @Override
   public abstract boolean equals(Object obj);
 
+  static Builder builder() {
+    return new AutoValue_ProductionBinding.Builder();
+  }
+
   /** A {@link ProductionBinding} builder. */
   @AutoValue.Builder
-  public abstract static class Builder
-      extends ContributionBinding.Builder<ProductionBinding, Builder> {
-
-    @CanIgnoreReturnValue
-    @Override
-    public Builder dependencies(Iterable<DependencyRequest> dependencies) {
-      return explicitDependencies(dependencies);
-    }
-
-    abstract Builder explicitDependencies(Iterable<DependencyRequest> dependencies);
-
-    abstract Builder productionKind(ProductionKind productionKind);
-
-    @Override
-    public abstract Builder unresolved(ProductionBinding unresolved);
-
-    abstract Builder thrownTypes(Iterable<XType> thrownTypes);
-
+  abstract static class Builder extends ContributionBinding.Builder<ProductionBinding, Builder> {
     abstract Builder executorRequest(DependencyRequest executorRequest);
 
     abstract Builder monitorRequest(DependencyRequest monitorRequest);
+
+    abstract Builder explicitDependencies(Iterable<DependencyRequest> explicitDependencies);
   }
 }
diff --git a/java/dagger/internal/codegen/binding/ProvisionBinding.java b/java/dagger/internal/codegen/binding/ProvisionBinding.java
index caf5904..7644155 100644
--- a/java/dagger/internal/codegen/binding/ProvisionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProvisionBinding.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Dagger Authors.
+ * Copyright (C) 2024 The Dagger Authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,88 +16,33 @@
 
 package dagger.internal.codegen.binding;
 
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.internal.codegen.model.BindingKind.PROVISION;
-
 import com.google.auto.value.AutoValue;
 import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.base.ContributionType;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.model.Key;
-import dagger.internal.codegen.model.Scope;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.Optional;
 
-/** A value object representing the mechanism by which a {@link Key} can be provided. */
+/** A binding for a {@link BindingKind#PROVISION}. */
 @CheckReturnValue
 @AutoValue
 public abstract class ProvisionBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.PROVISION;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
 
   @Override
   @Memoized
-  public ImmutableSet<DependencyRequest> explicitDependencies() {
-    return ImmutableSet.<DependencyRequest>builder()
-        .addAll(provisionDependencies())
-        .addAll(membersInjectionDependencies())
-        .build();
-  }
-
-  /**
-   * Dependencies necessary to invoke an {@code @Inject} constructor or {@code @Provides} method.
-   */
-  public abstract ImmutableSet<DependencyRequest> provisionDependencies();
-
-  @Memoized
-  ImmutableSet<DependencyRequest> membersInjectionDependencies() {
-    return injectionSites()
-        .stream()
-        .flatMap(i -> i.dependencies().stream())
-        .collect(toImmutableSet());
-  }
-
-  /**
-   * {@link InjectionSite}s for all {@code @Inject} members if {@link #kind()} is {@link
-   * BindingKind#INJECTION}, otherwise empty.
-   */
-  public abstract ImmutableSortedSet<InjectionSite> injectionSites();
-
-  @Override
-  public BindingType bindingType() {
-    return BindingType.PROVISION;
-  }
-
-  @Override
-  public abstract Optional<ProvisionBinding> unresolved();
-
-  // TODO(ronshapiro): we should be able to remove this, but AutoValue barks on the Builder's scope
-  // method, saying that the method doesn't correspond to a property of ProvisionBinding
-  @Override
-  public abstract Optional<Scope> scope();
-
-  public static Builder builder() {
-    return new AutoValue_ProvisionBinding.Builder()
-        .nullability(Nullability.NOT_NULLABLE)
-        .provisionDependencies(ImmutableSet.of())
-        .injectionSites(ImmutableSortedSet.of());
-  }
-
-  @Override
-  public abstract Builder toBuilder();
-
-  private static final ImmutableSet<BindingKind> KINDS_TO_CHECK_FOR_NULL =
-      ImmutableSet.of(PROVISION, COMPONENT_PROVISION);
-
-  public boolean shouldCheckForNull(CompilerOptions compilerOptions) {
-    return KINDS_TO_CHECK_FOR_NULL.contains(kind())
-        && !contributedPrimitiveType().isPresent()
-        && !isNullable()
-        && compilerOptions.doCheckForNulls();
+  public ContributionType contributionType() {
+    return ContributionType.fromBindingElement(bindingElement().get());
   }
 
   // Profiling determined that this method is called enough times that memoizing it had a measurable
@@ -108,6 +53,9 @@
     return super.requiresModuleInstance();
   }
 
+  @Override
+  public abstract Builder toBuilder();
+
   @Memoized
   @Override
   public abstract int hashCode();
@@ -116,26 +64,15 @@
   @Override
   public abstract boolean equals(Object obj);
 
-  /** A {@link ProvisionBinding} builder. */
-  @AutoValue.Builder
-  public abstract static class Builder
-      extends ContributionBinding.Builder<ProvisionBinding, Builder> {
-
-    @CanIgnoreReturnValue
-    @Override
-    public Builder dependencies(Iterable<DependencyRequest> dependencies) {
-      return provisionDependencies(dependencies);
-    }
-
-    abstract Builder provisionDependencies(Iterable<DependencyRequest> provisionDependencies);
-
-    public abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
-
-    @CanIgnoreReturnValue // TODO(kak): remove this once open-source checkers understand AutoValue
-    @Override
-    public abstract Builder unresolved(ProvisionBinding unresolved);
-
-    public abstract Builder scope(Optional<Scope> scope);
+  static Builder builder() {
+    return new AutoValue_ProvisionBinding.Builder();
   }
 
+  /** A {@link ProvisionBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder extends ContributionBinding.Builder<ProvisionBinding, Builder> {
+    abstract Builder nullability(Nullability nullability);
+
+    abstract Builder dependencies(Iterable<DependencyRequest> dependencies);
+  }
 }
diff --git a/java/dagger/internal/codegen/binding/ResolvedBindings.java b/java/dagger/internal/codegen/binding/ResolvedBindings.java
index 406ae41..6ead759 100644
--- a/java/dagger/internal/codegen/binding/ResolvedBindings.java
+++ b/java/dagger/internal/codegen/binding/ResolvedBindings.java
@@ -16,17 +16,12 @@
 
 package dagger.internal.codegen.binding;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
 
-import androidx.room.compiler.processing.XTypeElement;
 import com.google.auto.value.AutoValue;
 import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimap;
 import dagger.internal.codegen.model.ComponentPath;
 import dagger.internal.codegen.model.Key;
 
@@ -41,32 +36,26 @@
  */
 @AutoValue
 abstract class ResolvedBindings {
-  /** The component path for the resolved bindings. */
-  abstract ComponentPath componentPath();
+  /** Creates a {@link ResolvedBindings} appropriate for when there are no bindings for a key. */
+  static ResolvedBindings create(Key key) {
+    return create(key, ImmutableSet.of());
+  }
+
+  /** Creates a {@link ResolvedBindings} for a single binding. */
+  static ResolvedBindings create(Key key, BindingNode bindingNode) {
+    return create(key, ImmutableSet.of(bindingNode));
+  }
+
+  /** Creates a {@link ResolvedBindings} for multiple bindings. */
+  static ResolvedBindings create(Key key, ImmutableSet<BindingNode> bindingNodes) {
+    return new AutoValue_ResolvedBindings(key, bindingNodes);
+  }
 
   /** The binding key for which the {@link #bindings()} have been resolved. */
   abstract Key key();
 
-  /**
-   * The {@link ContributionBinding}s for {@link #key()} indexed by the component that owns the
-   * binding. Each key in the multimap is a part of the same component ancestry.
-   */
-  abstract ImmutableSetMultimap<XTypeElement, ContributionBinding> allContributionBindings();
-
-  /**
-   * The {@link MembersInjectionBinding}s for {@link #key()} indexed by the component that owns the
-   * binding. Each key in the map is a part of the same component ancestry.
-   */
-  abstract ImmutableMap<XTypeElement, MembersInjectionBinding> allMembersInjectionBindings();
-
-  /** The multibinding declarations for {@link #key()}. */
-  abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
-
-  /** The subcomponent declarations for {@link #key()}. */
-  abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
-
-  /** The optional binding declarations for {@link #key()}. */
-  abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
+  /** All binding nodes for {@link #key()}, regardless of which component owns them. */
+  abstract ImmutableSet<BindingNode> bindingNodes();
 
   // Computing the hash code is an expensive operation.
   @Memoized
@@ -77,105 +66,29 @@
   @Override
   public abstract boolean equals(Object other);
 
-  /** All bindings for {@link #key()}, indexed by the component that owns the binding. */
-  final ImmutableSetMultimap<XTypeElement, ? extends Binding> allBindings() {
-    return !allMembersInjectionBindings().isEmpty()
-        ? allMembersInjectionBindings().asMultimap()
-        : allContributionBindings();
-  }
-
   /** All bindings for {@link #key()}, regardless of which component owns them. */
-  final ImmutableCollection<? extends Binding> bindings() {
-    return allBindings().values();
+  final ImmutableSet<Binding> bindings() {
+    return bindingNodes().stream()
+        .map(BindingNode::delegate)
+        .collect(toImmutableSet());
   }
 
-  /**
-   * {@code true} if there are no {@link #bindings()}, {@link #multibindingDeclarations()}, {@link
-   * #optionalBindingDeclarations()}, or {@link #subcomponentDeclarations()}.
-   */
+  /** Returns {@code true} if there are no {@link #bindings()}. */
   final boolean isEmpty() {
-    return allMembersInjectionBindings().isEmpty()
-        && allContributionBindings().isEmpty()
-        && multibindingDeclarations().isEmpty()
-        && optionalBindingDeclarations().isEmpty()
-        && subcomponentDeclarations().isEmpty();
+    return bindingNodes().isEmpty();
   }
 
   /** All bindings for {@link #key()} that are owned by a component. */
-  ImmutableSet<? extends Binding> bindingsOwnedBy(ComponentDescriptor component) {
-    return allBindings().get(component.typeElement());
+  ImmutableSet<BindingNode> bindingNodesOwnedBy(ComponentPath componentPath) {
+    return bindingNodes().stream()
+        .filter(bindingNode -> bindingNode.componentPath().equals(componentPath))
+        .collect(toImmutableSet());
   }
 
-  /**
-   * All contribution bindings, regardless of owning component. Empty if this is a members-injection
-   * binding.
-   */
-  @Memoized
-  ImmutableSet<ContributionBinding> contributionBindings() {
-    // TODO(ronshapiro): consider optimizing ImmutableSet.copyOf(Collection) for small immutable
-    // collections so that it doesn't need to call toArray(). Even though this method is memoized,
-    // toArray() can take ~150ms for large components, and there are surely other places in the
-    // processor that can benefit from this.
-    return ImmutableSet.copyOf(allContributionBindings().values());
-  }
-
-  /** The component that owns {@code binding}. */
-  final XTypeElement owningComponent(ContributionBinding binding) {
-    checkArgument(
-        contributionBindings().contains(binding),
-        "binding is not resolved for %s: %s",
-        key(),
-        binding);
-    return getOnlyElement(allContributionBindings().inverse().get(binding));
-  }
-
-  /** Creates a {@link ResolvedBindings} for contribution bindings. */
-  static ResolvedBindings forContributionBindings(
-      ComponentPath componentPath,
-      Key key,
-      Multimap<XTypeElement, ContributionBinding> contributionBindings,
-      Iterable<MultibindingDeclaration> multibindings,
-      Iterable<SubcomponentDeclaration> subcomponentDeclarations,
-      Iterable<OptionalBindingDeclaration> optionalBindingDeclarations) {
-    return new AutoValue_ResolvedBindings(
-        componentPath,
-        key,
-        ImmutableSetMultimap.copyOf(contributionBindings),
-        ImmutableMap.of(),
-        ImmutableSet.copyOf(multibindings),
-        ImmutableSet.copyOf(subcomponentDeclarations),
-        ImmutableSet.copyOf(optionalBindingDeclarations));
-  }
-
-  /**
-   * Creates a {@link ResolvedBindings} for members injection bindings.
-   */
-  static ResolvedBindings forMembersInjectionBinding(
-      ComponentPath componentPath,
-      Key key,
-      ComponentDescriptor owningComponent,
-      MembersInjectionBinding ownedMembersInjectionBinding) {
-    return new AutoValue_ResolvedBindings(
-        componentPath,
-        key,
-        ImmutableSetMultimap.of(),
-        ImmutableMap.of(owningComponent.typeElement(), ownedMembersInjectionBinding),
-        ImmutableSet.of(),
-        ImmutableSet.of(),
-        ImmutableSet.of());
-  }
-
-  /**
-   * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
-   */
-  static ResolvedBindings noBindings(ComponentPath componentPath, Key key) {
-    return new AutoValue_ResolvedBindings(
-        componentPath,
-        key,
-        ImmutableSetMultimap.of(),
-        ImmutableMap.of(),
-        ImmutableSet.of(),
-        ImmutableSet.of(),
-        ImmutableSet.of());
+  /** Returns the binding node representing the given binding, or throws ISE if none exist. */
+  final BindingNode forBinding(Binding binding) {
+    return bindingNodes().stream()
+        .filter(bindingNode -> bindingNode.delegate().equals(binding))
+        .collect(onlyElement());
   }
 }
diff --git a/java/dagger/internal/codegen/binding/SourceFiles.java b/java/dagger/internal/codegen/binding/SourceFiles.java
index e8a1075..8319181 100644
--- a/java/dagger/internal/codegen/binding/SourceFiles.java
+++ b/java/dagger/internal/codegen/binding/SourceFiles.java
@@ -16,36 +16,30 @@
 
 package dagger.internal.codegen.binding;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static androidx.room.compiler.processing.XElementKt.isConstructor;
 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Verify.verify;
 import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCED_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCER_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_PROVIDER_FACTORY;
 import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
 import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
 import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY;
-import static dagger.internal.codegen.javapoet.TypeNames.SET_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.SET_OF_PRODUCED_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.SET_PRODUCER;
 import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
 import static dagger.internal.codegen.model.BindingKind.INJECTION;
-import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_SET;
 import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
 import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
+import static dagger.internal.codegen.xprocessing.XTypeNames.simpleName;
 import static javax.lang.model.SourceVersion.isName;
 
+import androidx.room.compiler.codegen.XClassName;
 import androidx.room.compiler.processing.XExecutableElement;
 import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
@@ -61,9 +55,11 @@
 import com.squareup.javapoet.TypeVariableName;
 import dagger.internal.codegen.base.MapType;
 import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.RequestKind;
+import dagger.internal.codegen.xprocessing.XTypeNames;
 import javax.inject.Inject;
 import javax.lang.model.SourceVersion;
 
@@ -96,21 +92,12 @@
     return Maps.toMap(
         binding.dependencies(),
         dependency -> {
-          ClassName frameworkClassName =
+          XClassName frameworkClassName =
               frameworkTypeMapper.getFrameworkType(dependency.kind()).frameworkClassName();
-          // Remap factory fields back to javax.inject.Provider to maintain backwards compatibility
-          // for now. In a future release, we should change this to Dagger Provider. This will still
-          // be a breaking change, but keeping compatibility for a while should reduce the
-          // likelihood of breakages as it would require components built at much older versions
-          // using factories built at newer versions to break.
-          if (frameworkClassName.equals(TypeNames.DAGGER_PROVIDER)) {
-            frameworkClassName = TypeNames.PROVIDER;
-          }
           return FrameworkField.create(
-              ParameterizedTypeName.get(
-                  frameworkClassName,
-                  dependency.key().type().xprocessing().getTypeName()),
-              DependencyVariableNamer.name(dependency));
+              DependencyVariableNamer.name(dependency),
+              frameworkClassName,
+              dependency.key().type().xprocessing());
         });
   }
 
@@ -147,31 +134,39 @@
         dep -> frameworkTypeUsageStatement(CodeBlock.of("$N", fields.get(dep)), dep.kind()));
   }
 
+  public static String generatedProxyMethodName(ContributionBinding binding) {
+    switch (binding.kind()) {
+      case INJECTION:
+      case ASSISTED_INJECTION:
+        return "newInstance";
+      case PROVISION:
+        XMethodElement method = asMethod(binding.bindingElement().get());
+        String simpleName = getSimpleName(method);
+        // If the simple name is already defined in the factory, prepend "proxy" to the name.
+        return simpleName.contentEquals("get") || simpleName.contentEquals("create")
+            ? "proxy" + LOWER_CAMEL.to(UPPER_CAMEL, simpleName)
+            : simpleName;
+      default:
+        throw new AssertionError("Unexpected binding kind: " + binding);
+    }
+  }
+
   /** Returns the generated factory or members injector name for a binding. */
-  public static ClassName generatedClassNameForBinding(Binding binding) {
-    switch (binding.bindingType()) {
+  public static XClassName generatedClassNameForBinding(Binding binding) {
+    switch (binding.kind()) {
+      case ASSISTED_INJECTION:
+      case INJECTION:
       case PROVISION:
       case PRODUCTION:
-        ContributionBinding contribution = (ContributionBinding) binding;
-        switch (contribution.kind()) {
-          case ASSISTED_INJECTION:
-          case INJECTION:
-          case PROVISION:
-          case PRODUCTION:
-            return factoryNameForElement(asExecutable(binding.bindingElement().get()));
-
-          case ASSISTED_FACTORY:
-            return siblingClassName(asTypeElement(binding.bindingElement().get()), "_Impl");
-
-          default:
-            throw new AssertionError();
-        }
-
+        return factoryNameForElement(asExecutable(binding.bindingElement().get()));
+      case ASSISTED_FACTORY:
+        return siblingClassName(asTypeElement(binding.bindingElement().get()), "_Impl");
       case MEMBERS_INJECTION:
         return membersInjectorNameForType(
             ((MembersInjectionBinding) binding).membersInjectedType());
+      default:
+        throw new AssertionError();
     }
-    throw new AssertionError();
   }
 
   /**
@@ -182,35 +177,35 @@
    * #generatedClassNameForBinding(Binding)} instead since this method does not validate that the
    * given element is actually a binding element or not.
    */
-  public static ClassName factoryNameForElement(XExecutableElement element) {
+  public static XClassName factoryNameForElement(XExecutableElement element) {
     return elementBasedClassName(element, "Factory");
   }
 
   /**
-   * Calculates an appropriate {@link ClassName} for a generated class that is based on {@code
+   * Calculates an appropriate {@link XClassName} for a generated class that is based on {@code
    * element}, appending {@code suffix} at the end.
    *
-   * <p>This will always return a {@linkplain ClassName#topLevelClassName() top level class name},
-   * even if {@code element}'s enclosing class is a nested type.
+   * <p>This will always return a top level class name, even if {@code element}'s enclosing class is
+   * a nested type.
    */
-  public static ClassName elementBasedClassName(XExecutableElement element, String suffix) {
-    ClassName enclosingClassName = element.getEnclosingElement().getClassName();
+  public static XClassName elementBasedClassName(XExecutableElement element, String suffix) {
+    XClassName enclosingClassName = element.getEnclosingElement().asClassName();
     String methodName =
         isConstructor(element) ? "" : LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(element));
-    return ClassName.get(
-        enclosingClassName.packageName(),
+    return XClassName.Companion.get(
+        enclosingClassName.getPackageName(),
         classFileName(enclosingClassName) + "_" + methodName + suffix);
   }
 
   public static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) {
-    ClassName className = generatedClassNameForBinding(binding);
+    ClassName className = toJavaPoet(generatedClassNameForBinding(binding));
     ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
     return typeParameters.isEmpty()
         ? className
         : ParameterizedTypeName.get(className, Iterables.toArray(typeParameters, TypeName.class));
   }
 
-  public static ClassName membersInjectorNameForType(XTypeElement typeElement) {
+  public static XClassName membersInjectorNameForType(XTypeElement typeElement) {
     return siblingClassName(typeElement, "_MembersInjector");
   }
 
@@ -218,19 +213,42 @@
     return field.getEnclosingElement().getClassName().canonicalName() + "." + getSimpleName(field);
   }
 
-  public static String classFileName(ClassName className) {
-    return CLASS_FILE_NAME_JOINER.join(className.simpleNames());
+  /*
+   * TODO(ronshapiro): this isn't perfect, as collisions could still exist. Some examples:
+   *
+   *  - @Inject void members() {} will generate a method that conflicts with the instance
+   *    method `injectMembers(T)`
+   *  - Adding the index could conflict with another member:
+   *      @Inject void a(Object o) {}
+   *      @Inject void a(String s) {}
+   *      @Inject void a1(String s) {}
+   *
+   *    Here, Method a(String) will add the suffix "1", which will conflict with the method
+   *    generated for a1(String)
+   *  - Members named "members" or "methods" could also conflict with the {@code static} injection
+   *    method.
+   */
+  public static String membersInjectorMethodName(InjectionSite injectionSite) {
+    int index = injectionSite.indexAmongAtInjectMembersWithSameSimpleName();
+    String indexString = index == 0 ? "" : String.valueOf(index + 1);
+    return "inject"
+        + LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(injectionSite.element()))
+        + indexString;
   }
 
-  public static ClassName generatedMonitoringModuleName(XTypeElement componentElement) {
+  public static String classFileName(XClassName className) {
+    return CLASS_FILE_NAME_JOINER.join(className.getSimpleNames());
+  }
+
+  public static XClassName generatedMonitoringModuleName(XTypeElement componentElement) {
     return siblingClassName(componentElement, "_MonitoringModule");
   }
 
   // TODO(ronshapiro): when JavaPoet migration is complete, replace the duplicated code
   // which could use this.
-  private static ClassName siblingClassName(XTypeElement typeElement, String suffix) {
-    ClassName className = typeElement.getClassName();
-    return className.topLevelClassName().peerClass(classFileName(className) + suffix);
+  private static XClassName siblingClassName(XTypeElement typeElement, String suffix) {
+    XClassName className = typeElement.asClassName();
+    return XClassName.Companion.get(className.getPackageName(), classFileName(className) + suffix);
   }
 
   /**
@@ -243,31 +261,33 @@
    *       {@code Set<Produced<T>>}.
    * </ul>
    */
-  public static ClassName setFactoryClassName(ContributionBinding binding) {
-    checkArgument(binding.kind().equals(MULTIBOUND_SET));
-    if (binding.bindingType().equals(BindingType.PROVISION)) {
-      return SET_FACTORY;
-    } else {
-      SetType setType = SetType.from(binding.key());
-      return setType.elementsAreTypeOf(TypeNames.PRODUCED)
-          ? SET_OF_PRODUCED_PRODUCER
-          : SET_PRODUCER;
+  public static XClassName setFactoryClassName(MultiboundSetBinding binding) {
+    switch (binding.bindingType()) {
+      case PROVISION:
+        return XTypeNames.SET_FACTORY;
+      case PRODUCTION:
+        SetType setType = SetType.from(binding.key());
+        return setType.elementsAreTypeOf(TypeNames.PRODUCED)
+            ? XTypeNames.SET_OF_PRODUCED_PRODUCER
+            : XTypeNames.SET_PRODUCER;
+      default:
+        throw new IllegalArgumentException(binding.bindingType().toString());
     }
   }
 
   /** The {@link java.util.Map} factory class name appropriate for map bindings. */
-  public static ClassName mapFactoryClassName(ContributionBinding binding) {
-    checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind());
+  public static XClassName mapFactoryClassName(MultiboundMapBinding binding) {
     MapType mapType = MapType.from(binding.key());
     switch (binding.bindingType()) {
       case PROVISION:
-        return mapType.valuesAreTypeOf(PROVIDER) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
+        return mapType.valuesAreTypeOf(PROVIDER)
+            ? XTypeNames.MAP_PROVIDER_FACTORY : XTypeNames.MAP_FACTORY;
       case PRODUCTION:
         return mapType.valuesAreFrameworkType()
             ? mapType.valuesAreTypeOf(PRODUCER)
-                ? MAP_OF_PRODUCER_PRODUCER
-                : MAP_OF_PRODUCED_PRODUCER
-            : MAP_PRODUCER;
+                ? XTypeNames.MAP_OF_PRODUCER_PRODUCER
+                : XTypeNames.MAP_OF_PRODUCED_PRODUCER
+            : XTypeNames.MAP_PRODUCER;
       default:
         throw new IllegalArgumentException(binding.bindingType().toString());
     }
@@ -293,16 +313,15 @@
    */
   // TODO(gak): maybe this should be a function of TypeMirrors instead of Elements?
   public static String simpleVariableName(XTypeElement typeElement) {
-    return simpleVariableName(typeElement.getClassName());
+    return simpleVariableName(typeElement.asClassName());
   }
 
   /**
-   * Returns a name to be used for variables of the given {@linkplain ClassName}. Prefer
-   * semantically meaningful variable names, but if none can be derived, this will produce something
-   * readable.
+   * Returns a name to be used for variables of the given {@link XClassName}. Prefer semantically
+   * meaningful variable names, but if none can be derived, this will produce something readable.
    */
-  public static String simpleVariableName(ClassName className) {
-    String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, className.simpleName());
+  public static String simpleVariableName(XClassName className) {
+    String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, simpleName(className));
     String variableName = protectAgainstKeywords(candidateName);
     verify(isName(variableName), "'%s' was expected to be a valid variable name", variableName);
     return variableName;
diff --git a/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java b/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java
new file mode 100644
index 0000000..b236163
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.binding;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.xprocessing.Nullability;
+import java.util.Optional;
+
+/** A binding for a {@link BindingKind#SUBCOMPONENT_CREATOR}. */
+@CheckReturnValue
+@AutoValue
+public abstract class SubcomponentCreatorBinding extends ContributionBinding {
+  @Override
+  public BindingKind kind() {
+    return BindingKind.SUBCOMPONENT_CREATOR;
+  }
+
+  @Override
+  public Optional<BindingType> optionalBindingType() {
+    return Optional.of(BindingType.PROVISION);
+  }
+
+  @Override
+  public ContributionType contributionType() {
+    return ContributionType.UNIQUE;
+  }
+
+  @Override
+  public Nullability nullability() {
+    return Nullability.NOT_NULLABLE;
+  }
+
+  @Override
+  public ImmutableSet<DependencyRequest> dependencies() {
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public abstract Builder toBuilder();
+
+  @Memoized
+  @Override
+  public abstract int hashCode();
+
+  // TODO(ronshapiro,dpb): simplify the equality semantics
+  @Override
+  public abstract boolean equals(Object obj);
+
+  static Builder builder() {
+    return new AutoValue_SubcomponentCreatorBinding.Builder();
+  }
+
+  /** A {@link SubcomponentCreatorBinding} builder. */
+  @AutoValue.Builder
+  abstract static class Builder
+      extends ContributionBinding.Builder<SubcomponentCreatorBinding, Builder> {}
+}
diff --git a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
index 5df2dd9..a04c745 100644
--- a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
+++ b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
@@ -36,7 +36,7 @@
  * dagger.Module#subcomponents()}.
  */
 @AutoValue
-public abstract class SubcomponentDeclaration extends BindingDeclaration {
+public abstract class SubcomponentDeclaration extends Declaration {
   /**
    * Key for the {@link dagger.Subcomponent.Builder} or {@link
    * dagger.producers.ProductionSubcomponent.Builder} of {@link #subcomponentType()}.
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
index c826c3d..dab9cb8 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
@@ -42,8 +42,9 @@
       MissingBindingValidator validation7,
       NullableBindingValidator validation8,
       ProvisionDependencyOnProducerBindingValidator validation9,
-      SetMultibindingValidator validation10,
-      SubcomponentFactoryMethodValidator validation11) {
+      InvalidProductionBindingScopeValidator validation10,
+      SetMultibindingValidator validation11,
+      SubcomponentFactoryMethodValidator validation12) {
     ImmutableSet<ValidationBindingGraphPlugin> plugins =
         ImmutableSet.of(
             validation1,
@@ -56,7 +57,8 @@
             validation8,
             validation9,
             validation10,
-            validation11);
+            validation11,
+            validation12);
     if (compilerOptions.experimentalDaggerErrorMessages()) {
       return ImmutableSet.of(factory.create(plugins));
     } else {
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
index a2c53c4..0ed6641 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
@@ -50,7 +50,6 @@
 import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
 import dagger.internal.codegen.model.BindingGraph.Node;
 import dagger.internal.codegen.model.BindingKind;
-import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.DiagnosticReporter;
 import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
@@ -179,20 +178,26 @@
   }
 
   private String errorMessage(Cycle<Node> cycle, BindingGraph graph) {
-    StringBuilder message = new StringBuilder("Found a dependency cycle:");
-    ImmutableList<DependencyRequest> cycleRequests =
+    return "Found a dependency cycle:"
+        + "\n"
+        + dependencyRequestFormatter.formatEdges(cycleEdges(cycle, graph), graph)
+        + "\n"
+        + Formatter.INDENT
+        + "...";
+  }
+
+  private ImmutableList<DependencyEdge> cycleEdges(Cycle<Node> cycle, BindingGraph graph) {
+    ImmutableList<DependencyEdge> cycleEdges =
         cycle.endpointPairs().stream()
             // TODO(dpb): Would be nice to take the dependency graph here.
             .map(endpointPair -> nonCycleBreakingEdge(endpointPair, graph))
-            .map(DependencyEdge::dependencyRequest)
             .collect(toImmutableList())
             .reverse();
-    dependencyRequestFormatter.formatIndentedList(message, cycleRequests, 0);
-    message.append("\n")
-        .append(dependencyRequestFormatter.format(cycleRequests.get(0)))
-        .append("\n")
-        .append(Formatter.INDENT).append("...");
-    return message.toString();
+    // Add the first edge to the end of the list to complete the cycle.
+    return ImmutableList.<DependencyEdge>builder()
+        .addAll(cycleEdges)
+        .add(cycleEdges.get(0))
+        .build();
   }
 
   /**
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
index ea4d738..a15c67c 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
@@ -19,8 +19,9 @@
 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
 import static javax.tools.Diagnostic.Kind.ERROR;
 
+import androidx.room.compiler.processing.XProcessingEnv;
 import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.Binding;
 import dagger.internal.codegen.model.BindingGraph;
 import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
@@ -34,12 +35,12 @@
  */
 // TODO(dpb,beder): Validate this during @Inject/@Provides/@Produces validation.
 final class DependsOnProductionExecutorValidator extends ValidationBindingGraphPlugin {
-  private final CompilerOptions compilerOptions;
+  private final XProcessingEnv processingEnv;
   private final KeyFactory keyFactory;
 
   @Inject
-  DependsOnProductionExecutorValidator(CompilerOptions compilerOptions, KeyFactory keyFactory) {
-    this.compilerOptions = compilerOptions;
+  DependsOnProductionExecutorValidator(XProcessingEnv processingEnv, KeyFactory keyFactory) {
+    this.processingEnv = processingEnv;
     this.keyFactory = keyFactory;
   }
 
@@ -50,7 +51,7 @@
 
   @Override
   public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
-    if (!compilerOptions.usesProducers()) {
+    if (!usesProducers()) {
       return;
     }
 
@@ -69,4 +70,8 @@
     diagnosticReporter.reportBinding(
         ERROR, binding, "%s may not depend on the production executor", binding.key());
   }
+
+  private boolean usesProducers() {
+    return processingEnv.findTypeElement(TypeNames.PRODUCES) != null;
+  }
 }
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
index 5f4dcfc..e357898 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
@@ -38,9 +38,9 @@
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 import dagger.internal.codegen.base.Formatter;
-import dagger.internal.codegen.binding.BindingDeclaration;
-import dagger.internal.codegen.binding.BindingDeclarationFormatter;
 import dagger.internal.codegen.binding.BindingNode;
+import dagger.internal.codegen.binding.Declaration;
+import dagger.internal.codegen.binding.DeclarationFormatter;
 import dagger.internal.codegen.binding.MultibindingDeclaration;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.model.Binding;
@@ -70,13 +70,13 @@
   private static final Comparator<Binding> BY_LENGTH_OF_COMPONENT_PATH =
       comparing(binding -> binding.componentPath().components().size());
 
-  private final BindingDeclarationFormatter bindingDeclarationFormatter;
+  private final DeclarationFormatter declarationFormatter;
   private final CompilerOptions compilerOptions;
 
   @Inject
   DuplicateBindingsValidator(
-      BindingDeclarationFormatter bindingDeclarationFormatter, CompilerOptions compilerOptions) {
-    this.bindingDeclarationFormatter = bindingDeclarationFormatter;
+      DeclarationFormatter declarationFormatter, CompilerOptions compilerOptions) {
+    this.declarationFormatter = declarationFormatter;
     this.compilerOptions = compilerOptions;
   }
 
@@ -219,7 +219,7 @@
     return String.format(
         "\n%s%s [%s]",
         Formatter.INDENT,
-        bindingDeclarationFormatter.format(((BindingNode) binding).delegate()),
+        declarationFormatter.format(((BindingNode) binding).delegate()),
         binding.componentPath());
   }
 
@@ -244,7 +244,7 @@
           .append(multibindingTypeString(oneMultibinding))
           .append(" bindings and declarations:");
       formatDeclarations(message, 2, declarations(graph, multibindings));
-      ImmutableSet<BindingDeclaration> uniqueBindingDeclarations =
+      ImmutableSet<Declaration> uniqueBindingDeclarations =
           duplicateBindings.stream()
               .filter(binding -> !binding.kind().isMultibinding())
               .flatMap(binding -> declarations(graph, binding).stream())
@@ -267,25 +267,25 @@
   private void formatDeclarations(
       StringBuilder builder,
       int indentLevel,
-      Iterable<? extends BindingDeclaration> bindingDeclarations) {
-    bindingDeclarationFormatter.formatIndentedList(
+      Iterable<? extends Declaration> bindingDeclarations) {
+    declarationFormatter.formatIndentedList(
         builder, ImmutableList.copyOf(bindingDeclarations), indentLevel);
   }
 
-  private ImmutableSet<BindingDeclaration> declarations(
+  private ImmutableSet<Declaration> declarations(
       BindingGraph graph, ImmutableCollection<Binding> bindings) {
     return bindings.stream()
         .flatMap(binding -> declarations(graph, binding).stream())
         .distinct()
-        .sorted(BindingDeclaration.COMPARATOR)
+        .sorted(Declaration.COMPARATOR)
         .collect(toImmutableSet());
   }
 
-  private ImmutableSet<BindingDeclaration> declarations(BindingGraph graph, Binding binding) {
-    ImmutableSet.Builder<BindingDeclaration> declarations = ImmutableSet.builder();
+  private ImmutableSet<Declaration> declarations(BindingGraph graph, Binding binding) {
+    ImmutableSet.Builder<Declaration> declarations = ImmutableSet.builder();
     BindingNode bindingNode = (BindingNode) binding;
     bindingNode.associatedDeclarations().forEach(declarations::add);
-    if (bindingDeclarationFormatter.canFormat(bindingNode.delegate())) {
+    if (declarationFormatter.canFormat(bindingNode.delegate())) {
       declarations.add(bindingNode.delegate());
     } else {
       graph.requestedBindings(binding).stream()
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
index c1108a8..50198ef 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
@@ -21,11 +21,10 @@
 import static dagger.internal.codegen.model.BindingKind.INJECTION;
 import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
+import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.joining;
 import static javax.tools.Diagnostic.Kind.ERROR;
 
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimaps;
 import dagger.internal.codegen.base.Scopes;
 import dagger.internal.codegen.binding.MethodSignatureFormatter;
 import dagger.internal.codegen.compileroption.CompilerOptions;
@@ -35,8 +34,8 @@
 import dagger.internal.codegen.model.DiagnosticReporter;
 import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
 import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
+import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import javax.inject.Inject;
 import javax.tools.Diagnostic;
 
@@ -45,7 +44,6 @@
  * component.
  */
 final class IncompatiblyScopedBindingsValidator extends ValidationBindingGraphPlugin {
-
   private final MethodSignatureFormatter methodSignatureFormatter;
   private final CompilerOptions compilerOptions;
   private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
@@ -69,36 +67,36 @@
   public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
     DiagnosticMessageGenerator diagnosticMessageGenerator =
         diagnosticMessageGeneratorFactory.create(bindingGraph);
-    ImmutableSetMultimap.Builder<ComponentNode, dagger.internal.codegen.model.Binding>
-        incompatibleBindings = ImmutableSetMultimap.builder();
-    for (dagger.internal.codegen.model.Binding binding : bindingGraph.bindings()) {
-      binding
-          .scope()
-          .filter(scope -> !scope.isReusable())
-          .ifPresent(
-              scope -> {
-                ComponentNode componentNode =
-                    bindingGraph.componentNode(binding.componentPath()).get();
-                if (!componentNode.scopes().contains(scope)) {
-                  // @Inject bindings in module or subcomponent binding graphs will appear at the
-                  // properly scoped ancestor component, so ignore them here.
-                  if (binding.kind().equals(INJECTION)
-                      && (bindingGraph.rootComponentNode().isSubcomponent()
-                          || !bindingGraph.rootComponentNode().isRealComponent())) {
-                    return;
-                  }
-                  incompatibleBindings.put(componentNode, binding);
-                }
-              });
+    bindingGraph.bindings().stream()
+        .filter(binding -> hasIncompatibleScope(bindingGraph, binding))
+        .collect(groupingBy(binding -> owningComponent(bindingGraph, binding)))
+        .forEach((owningComponent, bindings) ->
+            report(owningComponent, bindings, diagnosticReporter, diagnosticMessageGenerator));
+  }
+
+  private static boolean hasIncompatibleScope(BindingGraph bindingGraph, Binding binding) {
+    if (binding.scope().isEmpty()
+            || binding.scope().get().isReusable()
+            // @Inject bindings in module or subcomponent binding graphs will appear at the
+            // properly scoped ancestor component, so ignore them here.
+            || (binding.kind() == INJECTION && isSubcomponentOrModuleRoot(bindingGraph))) {
+      return false;
     }
-    Multimaps.asMap(incompatibleBindings.build())
-        .forEach((componentNode, bindings) ->
-            report(componentNode, bindings, diagnosticReporter, diagnosticMessageGenerator));
+    return !owningComponent(bindingGraph, binding).scopes().contains(binding.scope().get());
+  }
+
+  private static boolean isSubcomponentOrModuleRoot(BindingGraph bindingGraph) {
+    ComponentNode rootComponent = bindingGraph.rootComponentNode();
+     return rootComponent.isSubcomponent() || !rootComponent.isRealComponent();
+  }
+
+  private static ComponentNode owningComponent(BindingGraph bindingGraph, Binding binding) {
+    return bindingGraph.componentNode(binding.componentPath()).get();
   }
 
   private void report(
       ComponentNode componentNode,
-      Set<Binding> bindings,
+      List<Binding> bindings,
       DiagnosticReporter diagnosticReporter,
       DiagnosticMessageGenerator diagnosticMessageGenerator) {
     Diagnostic.Kind diagnosticKind = ERROR;
@@ -128,7 +126,7 @@
     for (Binding binding : bindings) {
       message.append('\n').append(INDENT);
 
-      // TODO(dpb): Use BindingDeclarationFormatter.
+      // TODO(dpb): Use DeclarationFormatter.
       // But that doesn't print scopes for @Inject-constructed types.
       switch (binding.kind()) {
         case DELEGATE:
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
index 2151295..6455f29 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
@@ -33,7 +33,7 @@
 
   @Inject
   InjectBindingValidator(InjectValidator injectValidator) {
-    this.injectValidator = injectValidator.whenGeneratingCode();
+    this.injectValidator = injectValidator;
   }
 
   @Override
@@ -50,7 +50,8 @@
 
   private void validateInjectionBinding(Binding node, DiagnosticReporter diagnosticReporter) {
     ValidationReport typeReport =
-        injectValidator.validate(node.key().type().xprocessing().getTypeElement());
+        injectValidator.validateWhenGeneratingCode(
+            node.key().type().xprocessing().getTypeElement());
     for (Item item : typeReport.allItems()) {
       diagnosticReporter.reportBinding(item.kind(), node, item.message());
     }
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/InvalidProductionBindingScopeValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/InvalidProductionBindingScopeValidator.java
new file mode 100644
index 0000000..f8a510c
--- /dev/null
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/InvalidProductionBindingScopeValidator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.bindinggraphvalidation;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
+import javax.inject.Inject;
+
+/** Reports an error for each production binding type that is invalidly scoped. */
+final class InvalidProductionBindingScopeValidator extends ValidationBindingGraphPlugin {
+
+  @Inject
+  InvalidProductionBindingScopeValidator() {}
+
+  @Override
+  public String pluginName() {
+    return "Dagger/InvalidProductionBindingScope";
+  }
+
+  @Override
+  public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter reporter) {
+    // Note: ProducesMethodValidator validates that @Produces methods aren't scoped, but here we
+    // take that a step further and validate that anything that transitively depends on a @Produces
+    // method is also not scoped (i.e. all production binding types).
+    bindingGraph.bindings().stream()
+        .filter(Binding::isProduction)
+        .filter(binding -> binding.scope().isPresent())
+        .forEach(binding -> reporter.reportBinding(ERROR, binding, errorMessage(binding)));
+  }
+
+  private String errorMessage(Binding binding) {
+    return String.format(
+        "%s cannot be scoped because it delegates to an @Produces method.",
+        binding);
+  }
+}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
index 87e8771..8d92c6e 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
@@ -17,31 +17,31 @@
 package dagger.internal.codegen.bindinggraphvalidation;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Multimaps.filterKeys;
 import static dagger.internal.codegen.base.Formatter.INDENT;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
 import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
 import static javax.tools.Diagnostic.Kind.ERROR;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
 import com.squareup.javapoet.ClassName;
 import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.binding.BindingDeclaration;
-import dagger.internal.codegen.binding.BindingDeclarationFormatter;
 import dagger.internal.codegen.binding.BindingNode;
 import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.Declaration;
+import dagger.internal.codegen.binding.DeclarationFormatter;
 import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.Binding;
 import dagger.internal.codegen.model.BindingGraph;
 import dagger.internal.codegen.model.DiagnosticReporter;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Set;
 import javax.inject.Inject;
 
@@ -51,13 +51,13 @@
  */
 final class MapMultibindingValidator extends ValidationBindingGraphPlugin {
 
-  private final BindingDeclarationFormatter bindingDeclarationFormatter;
+  private final DeclarationFormatter declarationFormatter;
   private final KeyFactory keyFactory;
 
   @Inject
   MapMultibindingValidator(
-      BindingDeclarationFormatter bindingDeclarationFormatter, KeyFactory keyFactory) {
-    this.bindingDeclarationFormatter = bindingDeclarationFormatter;
+      DeclarationFormatter declarationFormatter, KeyFactory keyFactory) {
+    this.declarationFormatter = declarationFormatter;
     this.keyFactory = keyFactory;
   }
 
@@ -90,41 +90,19 @@
    * </ol>
    */
   private ImmutableSet<Binding> mapMultibindings(BindingGraph bindingGraph) {
-    ImmutableSetMultimap<Key, Binding> mapMultibindings =
-        bindingGraph.bindings().stream()
-            .filter(node -> node.kind().equals(MULTIBOUND_MAP))
-            .collect(toImmutableSetMultimap(Binding::key, node -> node));
+    Set<Key> visitedKeys = new HashSet<>();
+    return bindingGraph.bindings().stream()
+        .filter(binding -> binding.kind().equals(MULTIBOUND_MAP))
+        // Sort by the order of the value in the RequestKind:
+        // (Map<K, V>, then Map<K, Provider<V>>, then Map<K, Producer<V>>).
+        .sorted(Comparator.comparing(binding -> MapType.from(binding.key()).valueRequestKind()))
+        // Only take the first binding (post sorting) per unwrapped key.
+        .filter(binding -> visitedKeys.add(unwrappedKey(binding)))
+        .collect(toImmutableSet());
+  }
 
-    // Mutlbindings for Map<K, V>
-    SetMultimap<Key, Binding> plainValueMapMultibindings =
-        filterKeys(mapMultibindings, key -> !MapType.from(key).valuesAreFrameworkType());
-
-    // Multibindings for Map<K, Provider<V>> where Map<K, V> isn't in plainValueMapMultibindings
-    SetMultimap<Key, Binding> providerValueMapMultibindings =
-        filterKeys(
-            mapMultibindings,
-            key ->
-                MapType.from(key).valuesAreTypeOf(TypeNames.PROVIDER)
-                    && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key)));
-
-    // Multibindings for Map<K, Producer<V>> where Map<K, V> isn't in plainValueMapMultibindings and
-    // Map<K, Provider<V>> isn't in providerValueMapMultibindings
-    SetMultimap<Key, Binding> producerValueMapMultibindings =
-        filterKeys(
-            mapMultibindings,
-            key ->
-                MapType.from(key).valuesAreTypeOf(TypeNames.PRODUCER)
-                    && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key))
-                    && !providerValueMapMultibindings.containsKey(
-                        keyFactory
-                            .rewrapMapKey(key, TypeNames.PRODUCER, TypeNames.PROVIDER)
-                            .get()));
-
-    return new ImmutableSet.Builder<Binding>()
-        .addAll(plainValueMapMultibindings.values())
-        .addAll(providerValueMapMultibindings.values())
-        .addAll(producerValueMapMultibindings.values())
-        .build();
+  private Key unwrappedKey(Binding binding) {
+    return keyFactory.unwrapMapValueType(binding.key());
   }
 
   private ImmutableSet<ContributionBinding> mapBindingContributions(
@@ -141,7 +119,11 @@
       ImmutableSet<ContributionBinding> contributions,
       DiagnosticReporter diagnosticReporter) {
     ImmutableSetMultimap<?, ContributionBinding> contributionsByMapKey =
-        ImmutableSetMultimap.copyOf(Multimaps.index(contributions, ContributionBinding::mapKey));
+        ImmutableSetMultimap.copyOf(
+            Multimaps.index(
+                contributions,
+                // Note: We're wrapping in XAnnotations.equivalence() to get proper equals/hashcode.
+                binding -> binding.mapKey().map(XAnnotations.equivalence()::wrap)));
 
     for (Set<ContributionBinding> contributionsForOneMapKey :
         Multimaps.asMap(contributionsByMapKey).values()) {
@@ -160,7 +142,7 @@
       DiagnosticReporter diagnosticReporter) {
     ImmutableSetMultimap<ClassName, ContributionBinding> contributionsByMapKeyAnnotationType =
         ImmutableSetMultimap.copyOf(
-            Multimaps.index(contributions, mapBinding -> mapBinding.mapKey().get().className()));
+            Multimaps.index(contributions, mapBinding -> getClassName(mapBinding.mapKey().get())));
 
     if (contributionsByMapKeyAnnotationType.keySet().size() > 1) {
       diagnosticReporter.reportBinding(
@@ -181,7 +163,7 @@
         .forEach(
             (annotationType, contributions) -> {
               message.append('\n').append(INDENT).append(annotationType).append(':');
-              bindingDeclarationFormatter.formatIndentedList(message, contributions, 2);
+              declarationFormatter.formatIndentedList(message, contributions, 2);
             });
     return message.toString();
   }
@@ -191,9 +173,9 @@
     StringBuilder message =
         new StringBuilder("The same map key is bound more than once for ").append(mapBindingKey);
 
-    bindingDeclarationFormatter.formatIndentedList(
+    declarationFormatter.formatIndentedList(
         message,
-        ImmutableList.sortedCopyOf(BindingDeclaration.COMPARATOR, contributionsForOneMapKey),
+        ImmutableList.sortedCopyOf(Declaration.COMPARATOR, contributionsForOneMapKey),
         1);
     return message.toString();
   }
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
index fd9e42e..f211717 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
@@ -18,13 +18,12 @@
 
 import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
 import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getLast;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.base.ElementFormatter.elementToString;
 import static dagger.internal.codegen.base.Formatter.INDENT;
 import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
 import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
-import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
+import static dagger.internal.codegen.base.RequestKinds.dependencyCanBeProduction;
 import static dagger.internal.codegen.binding.DependencyRequestFormatter.DOUBLE_INDENT;
 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
@@ -40,16 +39,12 @@
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.WildcardTypeName;
 import dagger.internal.codegen.binding.ComponentNodeImpl;
-import dagger.internal.codegen.binding.DependencyRequestFormatter;
 import dagger.internal.codegen.binding.InjectBindingRegistry;
 import dagger.internal.codegen.model.Binding;
 import dagger.internal.codegen.model.BindingGraph;
-import dagger.internal.codegen.model.BindingGraph.ComponentNode;
 import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
-import dagger.internal.codegen.model.BindingGraph.Edge;
 import dagger.internal.codegen.model.BindingGraph.MissingBinding;
-import dagger.internal.codegen.model.BindingGraph.Node;
-import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DaggerType;
 import dagger.internal.codegen.model.DiagnosticReporter;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
@@ -58,24 +53,19 @@
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
 import javax.inject.Inject;
 
 /** Reports errors for missing bindings. */
 final class MissingBindingValidator extends ValidationBindingGraphPlugin {
 
   private final InjectBindingRegistry injectBindingRegistry;
-  private final DependencyRequestFormatter dependencyRequestFormatter;
   private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
 
   @Inject
   MissingBindingValidator(
       InjectBindingRegistry injectBindingRegistry,
-      DependencyRequestFormatter dependencyRequestFormatter,
       DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
     this.injectBindingRegistry = injectBindingRegistry;
-    this.dependencyRequestFormatter = dependencyRequestFormatter;
     this.diagnosticMessageGeneratorFactory = diagnosticMessageGeneratorFactory;
   }
 
@@ -115,24 +105,28 @@
         ERROR,
         graph.componentNode(missingBinding.componentPath()).get(),
         missingBindingErrorMessage(missingBinding, graph)
-            + missingBindingDependencyTraceMessage(missingBinding, graph)
+            + diagnosticMessageGeneratorFactory.create(graph).getMessage(missingBinding)
             + alternativeBindingsMessage(missingBinding, graph)
             + similarBindingsMessage(missingBinding, graph));
   }
 
   private static ImmutableSet<Binding> getSimilarTypeBindings(
       BindingGraph graph, Key missingBindingKey) {
-    XType missingBindingType = missingBindingKey.type().xprocessing();
-    Optional<DaggerAnnotation> missingBindingQualifier = missingBindingKey.qualifier();
-    ImmutableList<TypeName> flatMissingBindingType = flattenBindingType(missingBindingType);
+    ImmutableList<TypeName> flatMissingBindingType = flattenBindingType(missingBindingKey.type());
     if (flatMissingBindingType.size() <= 1) {
       return ImmutableSet.of();
     }
     return graph.bindings().stream()
-        .filter(
-            binding ->
-                binding.key().qualifier().equals(missingBindingQualifier)
-                    && isSimilarType(binding.key().type().xprocessing(), flatMissingBindingType))
+        // Filter out multibinding contributions (users can't request these directly).
+        .filter(binding -> binding.key().multibindingContributionIdentifier().isEmpty())
+        // Filter out keys with the exact same type (those are reported elsewhere).
+        .filter(binding -> !binding.key().type().equals(missingBindingKey.type()))
+        // Filter out keys with different qualifiers.
+        // TODO(bcorso): We should consider allowing keys with different qualifiers here, as that
+        // could actually be helpful when users forget a qualifier annotation on the request.
+        .filter(binding -> binding.key().qualifier().equals(missingBindingKey.qualifier()))
+        // Filter out keys that don't have a similar type (i.e. same type if ignoring wildcards).
+        .filter(binding -> isSimilarType(binding.key().type(), flatMissingBindingType))
         .collect(toImmutableSet());
   }
 
@@ -140,11 +134,11 @@
    * Unwraps a parameterized type to a list of TypeNames. e.g. {@code Map<Foo, List<Bar>>} to {@code
    * [Map, Foo, List, Bar]}.
    */
-  private static ImmutableList<TypeName> flattenBindingType(XType type) {
+  private static ImmutableList<TypeName> flattenBindingType(DaggerType type) {
     return ImmutableList.copyOf(new TypeDfsIterator(type));
   }
 
-  private static boolean isSimilarType(XType type, List<TypeName> flatTypeNames) {
+  private static boolean isSimilarType(DaggerType type, ImmutableList<TypeName> flatTypeNames) {
     return Iterators.elementsEqual(flatTypeNames.iterator(), new TypeDfsIterator(type));
   }
 
@@ -178,36 +172,7 @@
       errorMessage.append(
           " This type supports members injection but cannot be implicitly provided.");
     }
-    return errorMessage.toString();
-  }
-
-  private String missingBindingDependencyTraceMessage(
-      MissingBinding missingBinding, BindingGraph graph) {
-    ImmutableSet<DependencyEdge> entryPoints =
-        graph.entryPointEdgesDependingOnBinding(missingBinding);
-    DiagnosticMessageGenerator generator = diagnosticMessageGeneratorFactory.create(graph);
-    ImmutableList<DependencyEdge> dependencyTrace =
-        generator.dependencyTrace(missingBinding, entryPoints);
-    StringBuilder message =
-        new StringBuilder(dependencyTrace.size() * 100 /* a guess heuristic */).append("\n");
-    for (DependencyEdge edge : dependencyTrace) {
-      String line = dependencyRequestFormatter.format(edge.dependencyRequest());
-      if (line.isEmpty()) {
-        continue;
-      }
-      // We don't have to check for cases where component names collide since
-      //  1. We always show the full classname of the component, and
-      //  2. We always show the full component path at the end of the dependency trace (below).
-      String componentName = String.format("[%s] ", getComponentFromDependencyEdge(edge, graph));
-      message.append("\n").append(line.replace(DOUBLE_INDENT, DOUBLE_INDENT + componentName));
-    }
-    if (!dependencyTrace.isEmpty()) {
-      generator.appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace), graph));
-    }
-    message.append(
-        generator.getRequestsNotInTrace(
-            dependencyTrace, generator.requests(missingBinding), entryPoints));
-    return message.toString();
+    return errorMessage.append("\n").toString();
   }
 
   private String alternativeBindingsMessage(
@@ -282,20 +247,6 @@
         .allMatch(edge -> dependencyCanBeProduction(edge, graph));
   }
 
-  // TODO(ronshapiro): merge with
-  // ProvisionDependencyOnProduerBindingValidator.dependencyCanUseProduction
-  private boolean dependencyCanBeProduction(DependencyEdge edge, BindingGraph graph) {
-    Node source = graph.network().incidentNodes(edge).source();
-    if (source instanceof ComponentNode) {
-      return canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind());
-    }
-    if (source instanceof Binding) {
-      return ((Binding) source).isProduction();
-    }
-    throw new IllegalArgumentException(
-        "expected a dagger.internal.codegen.model.Binding or ComponentNode: " + source);
-  }
-
   private boolean typeHasInjectionSites(Key key) {
     return injectBindingRegistry
         .getOrFindMembersInjectionBinding(key)
@@ -303,14 +254,6 @@
         .orElse(false);
   }
 
-  private static String getComponentFromDependencyEdge(DependencyEdge edge, BindingGraph graph) {
-    return source(edge, graph).componentPath().currentComponent().className().canonicalName();
-  }
-
-  private static Node source(Edge edge, BindingGraph graph) {
-    return graph.network().incidentNodes(edge).source();
-  }
-
   /**
    * An iterator over a list of TypeNames produced by flattening a parameterized type. e.g. {@code
    * Map<Foo, List<Bar>>} to {@code [Map, Foo, List, Bar]}.
@@ -320,8 +263,8 @@
   private static class TypeDfsIterator implements Iterator<TypeName> {
     final Deque<XType> stack = new ArrayDeque<>();
 
-    TypeDfsIterator(XType root) {
-      stack.push(root);
+    TypeDfsIterator(DaggerType root) {
+      stack.push(root.xprocessing());
     }
 
     @Override
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
index d8305df..90735ef 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
@@ -19,6 +19,7 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Verify.verify;
 import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
+import static dagger.internal.codegen.base.RequestKinds.dependencyCanBeProduction;
 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
 import static javax.tools.Diagnostic.Kind.ERROR;
 
@@ -64,7 +65,7 @@
     return bindingGraph.bindings().stream()
         .filter(binding -> binding.isProduction())
         .flatMap(binding -> incomingDependencies(binding, bindingGraph))
-        .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph));
+        .filter(edge -> !dependencyCanBeProduction(edge, bindingGraph));
   }
 
   /** Returns the dependencies on {@code binding}. */
@@ -74,13 +75,6 @@
         .flatMap(instancesOf(DependencyEdge.class));
   }
 
-  // TODO(ronshapiro): merge with MissingBindingValidator.dependencyCanUseProduction
-  private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) {
-    return edge.isEntryPoint()
-        ? canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind())
-        : bindingRequestingDependency(edge, bindingGraph).isProduction();
-  }
-
   /**
    * Returns the binding that requests a dependency.
    *
@@ -108,6 +102,12 @@
 
   private String dependencyErrorMessage(
       DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) {
+    if (!canBeSatisfiedByProductionBinding(
+        dependencyOnProduction.dependencyRequest().kind(), false)) {
+      return String.format(
+          "request kind %s cannot be satisfied by production binding.",
+          dependencyOnProduction.dependencyRequest().kind());
+    }
     return String.format(
         "%s is a provision, which cannot depend on a production.",
         bindingRequestingDependency(dependencyOnProduction, bindingGraph).key());
diff --git a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar b/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
index 6e4b0a9..5414d72 100644
--- a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
+++ b/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
Binary files differ
diff --git a/java/dagger/internal/codegen/compileroption/CompilerOptions.java b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
index 73f7736..0fb3635 100644
--- a/java/dagger/internal/codegen/compileroption/CompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
@@ -21,8 +21,6 @@
 
 /** A collection of options that dictate how the compiler will run. */
 public abstract class CompilerOptions {
-  public abstract boolean usesProducers();
-
   /**
    * Returns true if the fast initialization flag, {@code fastInit}, is enabled.
    *
@@ -56,15 +54,6 @@
    */
   public abstract boolean includeStacktraceWithDeferredErrorMessages();
 
-  /**
-   * If {@code true}, Dagger will generate factories and components even if some members-injected
-   * types have {@code private} or {@code static} {@code @Inject}-annotated members.
-   *
-   * <p>This should only ever be enabled by the TCK tests. Disabling this validation could lead to
-   * generating code that does not compile.
-   */
-  public abstract boolean ignorePrivateAndStaticInjectionForComponent();
-
   public abstract ValidationType scopeCycleValidationType();
 
   /**
@@ -129,6 +118,25 @@
    */
   public abstract boolean generatedClassExtendsComponent();
 
+  /**
+   * Returns {@code true} if Dagger should turn on the binding graph fix.
+   *
+   * <p>Note: This flag is only intended to give users time to migrate. This flag will be removed in
+   * a future release.
+   *
+   * <p>See https://dagger.dev/dev-guide/compiler-options#useBindingGraphFix for more details.
+   */
+  public abstract boolean useBindingGraphFix();
+
+  /**
+   * Returns {@code true} if the key for map multibinding contributions contain a framework type.
+   *
+   * <p>This option is for migration purposes only, and will be removed in a future release.
+   *
+   * <p>The default value is {@code false}.
+   */
+  public abstract boolean useFrameworkTypeInMapMultibindingContributionKey();
+
   /** Returns the number of bindings allowed per shard. */
   public int keysPerComponentShard(XTypeElement component) {
     return 3500;
diff --git a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
index 8138005..b94f8de 100644
--- a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
@@ -29,12 +29,13 @@
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.GENERATED_CLASS_EXTENDS_COMPONENT;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PROVISION_KEY_WILDCARDS;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_SUPERFICIAL_VALIDATION;
+import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.USE_BINDING_GRAPH_FIX;
+import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.USE_FRAMEWORK_TYPE_IN_MAP_MULTIBINDING_CONTRIBUTION_KEY;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM;
 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN;
@@ -61,7 +62,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.javapoet.TypeNames;
 import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashMap;
@@ -96,11 +96,6 @@
   }
 
   @Override
-  public boolean usesProducers() {
-    return processingEnv.findTypeElement(TypeNames.PRODUCES) != null;
-  }
-
-  @Override
   public boolean headerCompilation() {
     return isEnabled(HEADER_COMPILATION);
   }
@@ -145,11 +140,6 @@
   }
 
   @Override
-  public boolean ignorePrivateAndStaticInjectionForComponent() {
-    return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT);
-  }
-
-  @Override
   public ValidationType scopeCycleValidationType() {
     return parseOption(DISABLE_INTER_COMPONENT_SCOPE_VALIDATION);
   }
@@ -190,6 +180,11 @@
   }
 
   @Override
+  public boolean useFrameworkTypeInMapMultibindingContributionKey() {
+    return isEnabled(USE_FRAMEWORK_TYPE_IN_MAP_MULTIBINDING_CONTRIBUTION_KEY);
+  }
+
+  @Override
   public boolean ignoreProvisionKeyWildcards() {
     return isEnabled(IGNORE_PROVISION_KEY_WILDCARDS);
   }
@@ -210,6 +205,11 @@
   }
 
   @Override
+  public boolean useBindingGraphFix() {
+    return isEnabled(USE_BINDING_GRAPH_FIX);
+  }
+
+  @Override
   public int keysPerComponentShard(XTypeElement component) {
     if (options.containsKey(KEYS_PER_COMPONENT_SHARD)) {
       checkArgument(
@@ -244,15 +244,14 @@
     noLongerRecognized(FLOATING_BINDS_METHODS);
     noLongerRecognized(EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS);
     noLongerRecognized(USE_GRADLE_INCREMENTAL_PROCESSING);
-    if (!isEnabled(IGNORE_PROVISION_KEY_WILDCARDS)) {
-      if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP) {
-        processingEnv.getMessager().printMessage(
-            Diagnostic.Kind.ERROR,
-            String.format(
-                "When using KSP, you must also enable the '%s' compiler option (see %s).",
-                "dagger.ignoreProvisionKeyWildcards",
-                "https://dagger.dev/dev-guide/compiler-options#ignore-provision-key-wildcards"));
-      }
+    if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP
+        && !isEnabled(IGNORE_PROVISION_KEY_WILDCARDS)) {
+      processingEnv.getMessager().printMessage(
+          Diagnostic.Kind.ERROR,
+          String.format(
+              "When using KSP, you must also enable the '%s' compiler option (see %s).",
+              "dagger.ignoreProvisionKeyWildcards",
+              "https://dagger.dev/dev-guide/compiler-options#ignore-provision-key-wildcards"));
     }
     return this;
   }
@@ -325,8 +324,6 @@
 
     INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES,
 
-    IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT,
-
     EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS,
 
     FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS,
@@ -345,6 +342,10 @@
 
     GENERATED_CLASS_EXTENDS_COMPONENT,
 
+    USE_BINDING_GRAPH_FIX,
+
+    USE_FRAMEWORK_TYPE_IN_MAP_MULTIBINDING_CONTRIBUTION_KEY,
+
     IGNORE_PROVISION_KEY_WILDCARDS(ENABLED),
 
     VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED)
diff --git a/java/dagger/internal/codegen/componentgenerator/BUILD b/java/dagger/internal/codegen/componentgenerator/BUILD
index af10a01..6ba7e45 100644
--- a/java/dagger/internal/codegen/componentgenerator/BUILD
+++ b/java/dagger/internal/codegen/componentgenerator/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   A JSR-330 compliant dependency injection system for android and java
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java b/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
index 4214cbc..f2e2103 100644
--- a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
+++ b/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.componentgenerator;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.Preconditions.checkArgument;
@@ -90,7 +91,7 @@
 
   @Override
   public ImmutableList<TypeSpec.Builder> topLevelTypes(ComponentDescriptor componentDescriptor) {
-    ClassName generatedTypeName = getTopLevelClassName(componentDescriptor);
+    ClassName generatedTypeName = toJavaPoet(getTopLevelClassName(componentDescriptor));
     TypeSpec.Builder generatedComponent =
         TypeSpec.classBuilder(generatedTypeName)
             .addModifiers(FINAL)
diff --git a/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
index e7c5a44..284bc42 100644
--- a/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
+++ b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
@@ -32,11 +32,6 @@
   JavacPluginCompilerOptions() {}
 
   @Override
-  public boolean usesProducers() {
-    return true;
-  }
-
-  @Override
   public boolean fastInit(XTypeElement element) {
     return false;
   }
@@ -72,11 +67,6 @@
   }
 
   @Override
-  public boolean ignorePrivateAndStaticInjectionForComponent() {
-    return false;
-  }
-
-  @Override
   public ValidationType scopeCycleValidationType() {
     return NONE;
   }
@@ -122,6 +112,16 @@
   }
 
   @Override
+  public boolean useBindingGraphFix() {
+    return false;
+  }
+
+  @Override
+  public boolean useFrameworkTypeInMapMultibindingContributionKey() {
+    return false;
+  }
+
+  @Override
   public boolean strictMultibindingValidation() {
     return false;
   }
diff --git a/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java b/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
index 50ec8b1..bb090fc 100644
--- a/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
+++ b/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
@@ -31,8 +31,9 @@
     UNCHECKED("unchecked"),
     FUTURE_RETURN_VALUE_IGNORED("FutureReturnValueIgnored"),
     KOTLIN_INTERNAL("KotlinInternal", "KotlinInternalInJava"),
-    CAST("cast")
-    ;
+    CAST("cast"),
+    DEPRECATION("deprecation"),
+    UNINITIALIZED("nullness:initialization.field.uninitialized");
 
     private final ImmutableList<String> values;
 
diff --git a/java/dagger/internal/codegen/javapoet/TypeNames.java b/java/dagger/internal/codegen/javapoet/TypeNames.java
index ea89fc0..52e8928 100644
--- a/java/dagger/internal/codegen/javapoet/TypeNames.java
+++ b/java/dagger/internal/codegen/javapoet/TypeNames.java
@@ -61,7 +61,15 @@
   public static final ClassName LAZY_CLASS_KEY_MAP =
       ClassName.get("dagger.internal", "LazyClassKeyMap");
   public static final ClassName LAZY_CLASS_KEY_MAP_FACTORY =
-      ClassName.get("dagger.internal", "LazyClassKeyMap", "Factory");
+      ClassName.get("dagger.internal", "LazyClassKeyMap", "MapFactory");
+  public static final ClassName LAZY_CLASS_KEY_MAP_PROVIDER_FACTORY =
+      ClassName.get("dagger.internal", "LazyClassKeyMap", "MapProviderFactory");
+  public static final ClassName LAZY_MAP_OF_PRODUCED_PRODUCER =
+      ClassName.get("dagger.producers.internal", "LazyMapOfProducedProducer");
+  public static final ClassName LAZY_MAP_OF_PRODUCER_PRODUCER =
+      ClassName.get("dagger.producers.internal", "LazyMapOfProducerProducer");
+  public static final ClassName LAZY_MAP_PRODUCER =
+      ClassName.get("dagger.producers.internal", "LazyMapProducer");
 
   public static final ClassName DELEGATE_FACTORY =
       ClassName.get("dagger.internal", "DelegateFactory");
@@ -80,6 +88,7 @@
   public static final ClassName MEMBERS_INJECTORS =
       ClassName.get("dagger.internal", "MembersInjectors");
   public static final ClassName PROVIDER = ClassName.get("javax.inject", "Provider");
+  public static final ClassName JAKARTA_PROVIDER = ClassName.get("jakarta.inject", "Provider");
   public static final ClassName DAGGER_PROVIDER = ClassName.get("dagger.internal", "Provider");
   public static final ClassName DAGGER_PROVIDERS = ClassName.get("dagger.internal", "Providers");
   public static final ClassName PROVIDER_OF_LAZY =
diff --git a/java/dagger/internal/codegen/kotlin/BUILD b/java/dagger/internal/codegen/kotlin/BUILD
index 054ec89..ed750cd 100644
--- a/java/dagger/internal/codegen/kotlin/BUILD
+++ b/java/dagger/internal/codegen/kotlin/BUILD
@@ -15,13 +15,16 @@
 # Description:
 #   Sources related to Kotlin metadata.
 
-load("@rules_java//java:defs.bzl", "java_library")
+load("//tools:bazel_compat.bzl", "compat_kt_jvm_library")
 
 package(default_visibility = ["//:src"])
 
-java_library(
+compat_kt_jvm_library(
     name = "kotlin",
-    srcs = glob(["*.java"]),
+    srcs = glob([
+        "*.java",
+        "*.kt",
+    ]),
     plugins = ["//java/dagger/internal/codegen/bootstrap"],
     tags = ["maven:merged"],
     deps = [
@@ -36,7 +39,7 @@
         "//third_party/java/javapoet",
         "//third_party/java/jsr305_annotations",
         "//third_party/java/jsr330_inject",
+        "//third_party/kotlin/kotlin_metadata_jvm",
         "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
-        "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
     ],
 )
diff --git a/java/dagger/internal/codegen/kotlin/ClassMetadata.kt b/java/dagger/internal/codegen/kotlin/ClassMetadata.kt
new file mode 100644
index 0000000..737057b
--- /dev/null
+++ b/java/dagger/internal/codegen/kotlin/ClassMetadata.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.kotlin
+
+import androidx.room.compiler.processing.XAnnotation
+import androidx.room.compiler.processing.XFieldElement
+import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XTypeElement
+import kotlin.Metadata
+import kotlin.metadata.KmClass
+import kotlin.metadata.KmConstructor
+import kotlin.metadata.KmFunction
+import kotlin.metadata.KmProperty
+import kotlin.metadata.KmValueParameter
+import kotlin.metadata.jvm.KotlinClassMetadata
+import kotlin.metadata.jvm.signature
+import kotlin.metadata.jvm.fieldSignature
+import kotlin.metadata.jvm.getterSignature
+import kotlin.metadata.jvm.syntheticMethodForAnnotations
+
+/** Container classes for kotlin metadata types. */
+class ClassMetadata private constructor(private val kmClass: KmClass) {
+  val functionsBySignature = buildList<FunctionMetadata> {
+    addAll(kmClass.constructors.map { ConstructorMetadata(it) })
+    addAll(kmClass.functions.map { MethodMetadata(it) })
+  }.associateBy { it.signature }
+
+  val propertiesBySignature =
+      kmClass.properties
+          .filter { it.fieldSignature != null }
+          .map { PropertyMetadata(it) }
+          .associateBy { it.fieldSignature }
+
+  companion object {
+    /** Parse Kotlin class metadata from a given type element. */
+    @JvmStatic
+    fun of(typeElement: XTypeElement): ClassMetadata {
+      val metadataAnnotation = checkNotNull(typeElement.getAnnotation(Metadata::class)).value
+      return when (val classMetadata = KotlinClassMetadata.readStrict(metadataAnnotation)) {
+        is KotlinClassMetadata.Class -> ClassMetadata(classMetadata.kmClass)
+        else -> error("Unsupported metadata type: ${classMetadata}")
+      }
+    }
+  }
+}
+
+class ConstructorMetadata(private val kmConstructor: KmConstructor) : FunctionMetadata {
+  override val name = "<init>"
+  override val signature = kmConstructor.signature!!.toString()
+  override val parameters = kmConstructor.valueParameters.map { ParameterMetadata(it) }
+}
+
+class MethodMetadata(private val kmFunction: KmFunction) : FunctionMetadata {
+  override val name = kmFunction.name
+  override val signature = kmFunction.signature!!.toString()
+  override val parameters = kmFunction.valueParameters.map { ParameterMetadata(it) }
+}
+
+interface FunctionMetadata {
+  val name: String
+  val signature: String
+  val parameters: List<ParameterMetadata>
+}
+
+class PropertyMetadata(private val kmProperty: KmProperty) {
+  val name = kmProperty.name
+
+  /** Returns the JVM field descriptor of the backing field of this property. */
+  val fieldSignature = kmProperty.fieldSignature?.toString()
+
+  val getterSignature = kmProperty.getterSignature?.toString()
+
+  /** Returns JVM method descriptor of the synthetic method for property annotations. */
+  val methodForAnnotationsSignature = kmProperty.syntheticMethodForAnnotations?.toString()
+}
+
+class ParameterMetadata(private val kmValueParameter: KmValueParameter) {
+  val name = kmValueParameter.name
+}
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
index b27ae91..b06fd72 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
@@ -19,35 +19,18 @@
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 
-import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XFieldElement;
 import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.auto.value.AutoValue;
 import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import dagger.internal.codegen.extension.DaggerCollectors;
-import dagger.internal.codegen.javapoet.TypeNames;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import javax.annotation.Nullable;
-import kotlin.Metadata;
-import kotlinx.metadata.Flag;
-import kotlinx.metadata.KmClass;
-import kotlinx.metadata.KmConstructor;
-import kotlinx.metadata.KmFunction;
-import kotlinx.metadata.KmProperty;
-import kotlinx.metadata.jvm.JvmExtensionsKt;
-import kotlinx.metadata.jvm.JvmFieldSignature;
-import kotlinx.metadata.jvm.JvmMetadataUtil;
-import kotlinx.metadata.jvm.JvmMethodSignature;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
 
 /** Data class of a TypeElement and its Kotlin metadata. */
 @AutoValue
@@ -107,8 +90,7 @@
   }
 
   private Optional<MethodForAnnotations> getAnnotationMethodUncached(XFieldElement fieldElement) {
-    return findProperty(fieldElement)
-        .methodForAnnotationsSignature()
+    return Optional.ofNullable(findProperty(fieldElement).getMethodForAnnotationsSignature())
         .map(
             signature ->
                 Optional.ofNullable(methodDescriptors().get(signature))
@@ -125,20 +107,19 @@
   }
 
   private Optional<XMethodElement> getPropertyGetterUncached(XFieldElement fieldElement) {
-    return findProperty(fieldElement)
-        .getterSignature()
+    return Optional.ofNullable(findProperty(fieldElement).getGetterSignature())
         .flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature)));
   }
 
   private PropertyMetadata findProperty(XFieldElement field) {
     String fieldDescriptor = field.getJvmDescriptor();
-    if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) {
-      return classMetadata().propertiesByFieldSignature().get(fieldDescriptor);
+    if (classMetadata().getPropertiesBySignature().containsKey(fieldDescriptor)) {
+      return classMetadata().getPropertiesBySignature().get(fieldDescriptor);
     } else {
       // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124
       final String propertyName = getPropertyNameFromField(field);
-      return classMetadata().propertiesByFieldSignature().values().stream()
-          .filter(property -> propertyName.contentEquals(property.name()))
+      return classMetadata().getPropertiesBySignature().values().stream()
+          .filter(property -> propertyName.contentEquals(property.getName())) // SUPPRESS_GET_NAME_CHECK
           .collect(DaggerCollectors.onlyElement());
     }
   }
@@ -154,217 +135,7 @@
 
   /** Parse Kotlin class metadata from a given type element. */
   static KotlinMetadata from(XTypeElement typeElement) {
-    return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.create(metadataOf(typeElement)));
-  }
-
-  private static KotlinClassMetadata.Class metadataOf(XTypeElement typeElement) {
-    XAnnotation annotationMirror = typeElement.getAnnotation(TypeNames.KOTLIN_METADATA);
-    Preconditions.checkNotNull(annotationMirror);
-    Metadata metadataAnnotation =
-        JvmMetadataUtil.Metadata(
-            annotationMirror.getAsInt("k"),
-            annotationMirror.getAsIntList("mv").stream().mapToInt(Integer::intValue).toArray(),
-            annotationMirror.getAsStringList("d1").toArray(new String[0]),
-            annotationMirror.getAsStringList("d2").toArray(new String[0]),
-            annotationMirror.getAsString("xs"),
-            annotationMirror.getAnnotationValue("pn").hasStringValue()
-                ? annotationMirror.getAsString("pn")
-                : null,
-            annotationMirror.getAnnotationValue("xi").hasIntValue()
-                ? annotationMirror.getAsInt("xi")
-                : null);
-    KotlinClassMetadata metadata = KotlinClassMetadata.read(metadataAnnotation);
-    if (metadata == null) {
-      // Can happen if Kotlin < 1.0 or if metadata version is not supported, i.e.
-      // kotlinx-metadata-jvm is outdated.
-      throw new IllegalStateException(
-          "Unable to read Kotlin metadata due to unsupported metadata version.");
-    }
-    if (metadata instanceof KotlinClassMetadata.Class) {
-      // TODO(danysantiago): If when we need other types of metadata then move to right method.
-      return (KotlinClassMetadata.Class) metadata;
-    } else {
-      throw new IllegalStateException("Unsupported metadata type: " + metadata);
-    }
-  }
-
-  @AutoValue
-  abstract static class ClassMetadata extends BaseMetadata {
-    abstract Optional<String> companionObjectName();
-
-    abstract ImmutableSet<FunctionMetadata> constructors();
-
-    abstract ImmutableMap<String, FunctionMetadata> functionsBySignature();
-
-    abstract ImmutableMap<String, PropertyMetadata> propertiesByFieldSignature();
-
-    static ClassMetadata create(KotlinClassMetadata.Class metadata) {
-      KmClass kmClass = metadata.toKmClass();
-      ClassMetadata.Builder builder =
-          ClassMetadata.builder(
-              kmClass.getFlags(), kmClass.getName()); // // SUPPRESS_GET_NAME_CHECK
-      builder.companionObjectName(Optional.ofNullable(kmClass.getCompanionObject()));
-      kmClass.getConstructors().forEach(it -> builder.addConstructor(FunctionMetadata.create(it)));
-      kmClass.getFunctions().forEach(it -> builder.addFunction(FunctionMetadata.create(it)));
-      kmClass.getProperties().forEach(it -> builder.addProperty(PropertyMetadata.create(it)));
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_ClassMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    abstract static class Builder implements BaseMetadata.Builder<Builder> {
-      abstract Builder companionObjectName(Optional<String> companionObjectName);
-
-      abstract ImmutableSet.Builder<FunctionMetadata> constructorsBuilder();
-
-      abstract ImmutableMap.Builder<String, FunctionMetadata> functionsBySignatureBuilder();
-
-      abstract ImmutableMap.Builder<String, PropertyMetadata> propertiesByFieldSignatureBuilder();
-
-      Builder addConstructor(FunctionMetadata constructor) {
-        constructorsBuilder().add(constructor);
-        functionsBySignatureBuilder().put(constructor.signature(), constructor);
-        return this;
-      }
-
-      Builder addFunction(FunctionMetadata function) {
-        functionsBySignatureBuilder().put(function.signature(), function);
-        return this;
-      }
-
-      Builder addProperty(PropertyMetadata property) {
-        if (property.fieldSignature().isPresent()) {
-          propertiesByFieldSignatureBuilder().put(property.fieldSignature().get(), property);
-        }
-        return this;
-      }
-
-      abstract ClassMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class FunctionMetadata extends BaseMetadata {
-    abstract String signature();
-
-    abstract ImmutableList<ValueParameterMetadata> parameters();
-
-    static FunctionMetadata create(KmConstructor metadata) {
-      FunctionMetadata.Builder builder = FunctionMetadata.builder(metadata.getFlags(), "<init>");
-      metadata
-          .getValueParameters()
-          .forEach(
-              it ->
-                  builder.addParameter(
-                      ValueParameterMetadata.create(
-                          it.getFlags(), it.getName()))); // SUPPRESS_GET_NAME_CHECK
-      builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString());
-      return builder.build();
-    }
-
-    static FunctionMetadata create(KmFunction metadata) {
-      FunctionMetadata.Builder builder =
-          FunctionMetadata.builder(
-              metadata.getFlags(), metadata.getName()); // SUPPRESS_GET_NAME_CHECK
-      metadata
-          .getValueParameters()
-          .forEach(
-              it ->
-                  builder.addParameter(
-                      ValueParameterMetadata.create(
-                          it.getFlags(), it.getName()))); // SUPPRESS_GET_NAME_CHECK
-      builder.signature(Objects.requireNonNull(JvmExtensionsKt.getSignature(metadata)).asString());
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_FunctionMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    abstract static class Builder implements BaseMetadata.Builder<Builder> {
-      abstract Builder signature(String signature);
-
-      abstract ImmutableList.Builder<ValueParameterMetadata> parametersBuilder();
-
-      Builder addParameter(ValueParameterMetadata parameter) {
-        parametersBuilder().add(parameter);
-        return this;
-      }
-
-      abstract FunctionMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class PropertyMetadata extends BaseMetadata {
-    /** Returns the JVM field descriptor of the backing field of this property. */
-    abstract Optional<String> fieldSignature();
-
-    abstract Optional<String> getterSignature();
-
-    /** Returns JVM method descriptor of the synthetic method for property annotations. */
-    abstract Optional<String> methodForAnnotationsSignature();
-
-    static PropertyMetadata create(KmProperty metadata) {
-      PropertyMetadata.Builder builder =
-          PropertyMetadata.builder(
-              metadata.getFlags(), metadata.getName()); // SUPPRESS_GET_NAME_CHECK
-      builder.fieldSignature(
-          Optional.ofNullable(JvmExtensionsKt.getFieldSignature(metadata))
-              .map(JvmFieldSignature::asString));
-      builder.getterSignature(
-          Optional.ofNullable(JvmExtensionsKt.getGetterSignature(metadata))
-              .map(JvmMethodSignature::asString));
-      builder.methodForAnnotationsSignature(
-          Optional.ofNullable(JvmExtensionsKt.getSyntheticMethodForAnnotations(metadata))
-              .map(JvmMethodSignature::asString));
-      return builder.build();
-    }
-
-    private static Builder builder(int flags, String name) {
-      return new AutoValue_KotlinMetadata_PropertyMetadata.Builder().flags(flags).name(name);
-    }
-
-    @AutoValue.Builder
-    interface Builder extends BaseMetadata.Builder<Builder> {
-      Builder fieldSignature(Optional<String> signature);
-
-      Builder getterSignature(Optional<String> signature);
-
-      Builder methodForAnnotationsSignature(Optional<String> signature);
-
-      PropertyMetadata build();
-    }
-  }
-
-  @AutoValue
-  abstract static class ValueParameterMetadata extends BaseMetadata {
-    private static ValueParameterMetadata create(int flags, String name) {
-      return new AutoValue_KotlinMetadata_ValueParameterMetadata(flags, name);
-    }
-  }
-
-  abstract static class BaseMetadata {
-    /** Returns the Kotlin metadata flags for this property. */
-    abstract int flags();
-
-    /** returns {@code true} if the given flag (e.g. {@link Flag.IS_PRIVATE}) applies. */
-    boolean flags(Flag flag) {
-      return flag.invoke(flags());
-    }
-
-    /** Returns the simple name of this property. */
-    abstract String name();
-
-    interface Builder<BuilderT> {
-      BuilderT flags(int flags);
-
-      BuilderT name(String name);
-    }
+    return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.of(typeElement));
   }
 
   @AutoValue
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
index 991b81a..9f80b3b 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
@@ -29,7 +29,6 @@
 import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.kotlin.KotlinMetadata.FunctionMetadata;
 import java.util.Optional;
 import javax.inject.Inject;
 
@@ -86,7 +85,12 @@
   public ImmutableMap<String, String> getAllMethodNamesBySignature(XTypeElement element) {
     checkState(
         hasMetadata(element), "Can not call getAllMethodNamesBySignature for non-Kotlin class");
-    return metadataFactory.create(element).classMetadata().functionsBySignature().values().stream()
-        .collect(toImmutableMap(FunctionMetadata::signature, FunctionMetadata::name));
+    return metadataFactory.create(element)
+        .classMetadata()
+        .getFunctionsBySignature().values().stream()
+        .collect(
+            toImmutableMap(
+                FunctionMetadata::getSignature,
+                FunctionMetadata::getName)); // SUPPRESS_GET_NAME_CHECK
   }
 }
diff --git a/java/dagger/internal/codegen/kythe/BUILD b/java/dagger/internal/codegen/kythe/BUILD
index 217627d..09bc5c3 100644
--- a/java/dagger/internal/codegen/kythe/BUILD
+++ b/java/dagger/internal/codegen/kythe/BUILD
@@ -15,7 +15,7 @@
 # Description:
 #   A library for the kythe plugin.
 
-load("@rules_java//java:defs.bzl", "java_library")
+load("@rules_java//java:defs.bzl", "java_import", "java_library")
 
 package(default_visibility = ["//:src"])
 
@@ -41,8 +41,6 @@
     ],
 )
 
-load("@rules_java//java:defs.bzl", "java_import")
-
 # A _deploy.jar consisting of the java_librarys in https://github.com/kythe/kythe needed to build a
 # Kythe plugin
 # TODO(ronshapiro): replace this with a http_archive of the next release in
diff --git a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
index 0b8a502..a558f94 100644
--- a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
+++ b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
@@ -37,10 +37,10 @@
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import dagger.Component;
 import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingDeclaration;
 import dagger.internal.codegen.binding.BindingGraphFactory;
 import dagger.internal.codegen.binding.BindingNode;
 import dagger.internal.codegen.binding.ComponentDescriptor;
+import dagger.internal.codegen.binding.Declaration;
 import dagger.internal.codegen.binding.ModuleDescriptor;
 import dagger.internal.codegen.javac.JavacPluginModule;
 import dagger.internal.codegen.javapoet.TypeNames;
@@ -99,7 +99,7 @@
 
   /**
    * Add {@code /inject/satisfiedby} edges from {@code dependency}'s {@link
-   * DependencyRequest#requestElement()} to any {@link BindingDeclaration#bindingElement() binding
+   * DependencyRequest#requestElement()} to any {@link Declaration#bindingElement() binding
    * elements} that satisfy the request.
    *
    * <p>This collapses requests for synthetic bindings so that a request for a multibound key
@@ -122,18 +122,18 @@
         }
       }
     }
-    for (BindingDeclaration bindingDeclaration :
+    for (Declaration declaration :
         Iterables.concat(
             bindingNode.multibindingDeclarations(),
             bindingNode.optionalBindingDeclarations())) {
-      addDependencyEdge(dependency, bindingDeclaration);
+      addDependencyEdge(dependency, declaration);
     }
   }
 
   private void addDependencyEdge(
-      DependencyRequest dependency, BindingDeclaration bindingDeclaration) {
+      DependencyRequest dependency, Declaration declaration) {
     XElement requestElement = dependency.requestElement().get().xprocessing();
-    XElement bindingElement = bindingDeclaration.bindingElement().get();
+    XElement bindingElement = declaration.bindingElement().get();
     Optional<VName> requestElementNode = jvmNode(requestElement, "request element");
     Optional<VName> bindingElementNode = jvmNode(bindingElement, "binding element");
     emitEdge(requestElementNode, "/inject/satisfiedby", bindingElementNode);
diff --git a/java/dagger/internal/codegen/processingstep/AssistedFactoryProcessingStep.java b/java/dagger/internal/codegen/processingstep/AssistedFactoryProcessingStep.java
index ebd5d10..3d4c11b 100644
--- a/java/dagger/internal/codegen/processingstep/AssistedFactoryProcessingStep.java
+++ b/java/dagger/internal/codegen/processingstep/AssistedFactoryProcessingStep.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.processingstep;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethods;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
@@ -57,14 +58,14 @@
 import com.squareup.javapoet.ParameterizedTypeName;
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerationException;
 import dagger.internal.codegen.base.SourceFileGenerator;
+import dagger.internal.codegen.binding.AssistedFactoryBinding;
 import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
 import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
 import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
 import dagger.internal.codegen.binding.BindingFactory;
 import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.validation.ValidationReport;
 import dagger.internal.codegen.xprocessing.XTypes;
@@ -110,12 +111,8 @@
     ValidationReport report = new AssistedFactoryValidator().validate(factory);
     report.printMessagesTo(messager);
     if (report.isClean()) {
-      try {
-        ProvisionBinding binding = bindingFactory.assistedFactoryBinding(factory, Optional.empty());
-        new AssistedFactoryImplGenerator().generate(binding);
-      } catch (SourceFileGenerationException e) {
-        e.printMessageTo(messager);
-      }
+      new AssistedFactoryImplGenerator()
+          .generate(bindingFactory.assistedFactoryBinding(factory, Optional.empty()));
     }
   }
 
@@ -230,13 +227,14 @@
   }
 
   /** Generates an implementation of the {@link dagger.assisted.AssistedFactory}-annotated class. */
-  private final class AssistedFactoryImplGenerator extends SourceFileGenerator<ProvisionBinding> {
+  private final class AssistedFactoryImplGenerator
+      extends SourceFileGenerator<AssistedFactoryBinding> {
     AssistedFactoryImplGenerator() {
       super(filer, processingEnv);
     }
 
     @Override
-    public XElement originatingElement(ProvisionBinding binding) {
+    public XElement originatingElement(AssistedFactoryBinding binding) {
       return binding.bindingElement().get();
     }
 
@@ -273,10 +271,10 @@
     //   }
     // }
     @Override
-    public ImmutableList<TypeSpec.Builder> topLevelTypes(ProvisionBinding binding) {
+    public ImmutableList<TypeSpec.Builder> topLevelTypes(AssistedFactoryBinding binding) {
       XTypeElement factory = asTypeElement(binding.bindingElement().get());
 
-      ClassName name = generatedClassNameForBinding(binding);
+      ClassName name = toJavaPoet(generatedClassNameForBinding(binding));
       TypeSpec.Builder builder =
           TypeSpec.classBuilder(name)
               .addModifiers(PUBLIC, FINAL)
@@ -363,13 +361,14 @@
 
     /** Returns the generated factory {@link TypeName type} for an @AssistedInject constructor. */
     private TypeName delegateFactoryTypeName(XType assistedInjectType) {
+      AssistedInjectionBinding binding =
+          bindingFactory.assistedInjectionBinding(
+              getOnlyElement(assistedInjectedConstructors(assistedInjectType.getTypeElement())),
+              Optional.empty());
+
       // The name of the generated factory for the assisted inject type,
       // e.g. an @AssistedInject Foo(...) {...} constructor will generate a Foo_Factory class.
-      ClassName generatedFactoryClassName =
-          generatedClassNameForBinding(
-              bindingFactory.injectionBinding(
-                  getOnlyElement(assistedInjectedConstructors(assistedInjectType.getTypeElement())),
-                  Optional.empty()));
+      ClassName generatedFactoryClassName = toJavaPoet(generatedClassNameForBinding(binding));
 
       // Return the factory type resolved with the same type parameters as the assisted inject type.
       return assistedInjectType.getTypeArguments().isEmpty()
diff --git a/java/dagger/internal/codegen/processingstep/LazyClassKeyProcessingStep.java b/java/dagger/internal/codegen/processingstep/LazyClassKeyProcessingStep.java
new file mode 100644
index 0000000..1843c19
--- /dev/null
+++ b/java/dagger/internal/codegen/processingstep/LazyClassKeyProcessingStep.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.processingstep;
+
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.joining;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.writing.LazyMapKeyProxyGenerator;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+/** Generate keep rules for LazyClassKey referenced classes to prevent class merging. */
+final class LazyClassKeyProcessingStep extends TypeCheckingProcessingStep<XElement> {
+  private static final String PROGUARD_KEEP_RULE = "-keep,allowobfuscation,allowshrinking class ";
+
+  // Note: We aggregate @LazyClassKey usages across processing rounds, so we use ClassName instead
+  // of XElement as the map key to avoid storing XElement instances across processing rounds.
+  private final SetMultimap<ClassName, ClassName> lazyMapKeysByModule = LinkedHashMultimap.create();
+  private final LazyMapKeyProxyGenerator lazyMapKeyProxyGenerator;
+
+  @Inject
+  LazyClassKeyProcessingStep(LazyMapKeyProxyGenerator lazyMapKeyProxyGenerator) {
+    this.lazyMapKeyProxyGenerator = lazyMapKeyProxyGenerator;
+  }
+
+  @Override
+  public ImmutableSet<ClassName> annotationClassNames() {
+    return ImmutableSet.of(TypeNames.LAZY_CLASS_KEY);
+  }
+
+  @Override
+  protected void process(XElement element, ImmutableSet<ClassName> annotations) {
+    ClassName lazyClassKey =
+        element
+            .getAnnotation(TypeNames.LAZY_CLASS_KEY)
+            .getAsType("value")
+            .getTypeElement()
+            .getClassName();
+    // No need to fail, since we want to support customized usage of class key annotations.
+    // https://github.com/google/dagger/pull/2831
+    if (!isMapBinding(element) || !isModuleOrProducerModule(element.getEnclosingElement())) {
+      return;
+    }
+    XTypeElement moduleElement = XElements.asTypeElement(element.getEnclosingElement());
+    lazyMapKeysByModule.put(moduleElement.getClassName(), lazyClassKey);
+    XMethodElement method = XElements.asMethod(element);
+    lazyMapKeyProxyGenerator.generate(method);
+  }
+
+  private static boolean isMapBinding(XElement element) {
+    return element.hasAnnotation(TypeNames.INTO_MAP)
+        && (element.hasAnnotation(TypeNames.BINDS)
+            || element.hasAnnotation(TypeNames.PROVIDES)
+            || element.hasAnnotation(TypeNames.PRODUCES));
+  }
+
+  private static boolean isModuleOrProducerModule(XElement element) {
+    return isTypeElement(element)
+        && (element.hasAnnotation(TypeNames.MODULE)
+            || element.hasAnnotation(TypeNames.PRODUCER_MODULE));
+  }
+
+  // TODO(b/386393062): Avoid generating proguard files in processOver.
+  @Override
+  public void processOver(
+      XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {
+    super.processOver(env, elementsByAnnotation);
+    lazyMapKeysByModule
+        .asMap()
+        .forEach(
+            (moduleClassName, lazyClassKeys) -> {
+              // Note: we could probably get better incremental performance by using the method
+              // element instead of the module element as the originating element. However, that
+              // would require appending the method name to each proguard file, which would probably
+              // cause issues with the filename length limit (256 characters) given it already must
+              // include the module's fully qualified name.
+              XTypeElement originatingElement =
+                  env.requireTypeElement(moduleClassName.canonicalName());
+
+              Path proguardFile =
+                  Path.of(
+                      "META-INF/proguard",
+                      getFullyQualifiedEnclosedClassName(moduleClassName) + "_LazyClassKeys.pro");
+
+              String proguardFileContents =
+                  lazyClassKeys.stream()
+                      .map(lazyClassKey -> PROGUARD_KEEP_RULE + lazyClassKey.canonicalName())
+                      .collect(joining("\n"));
+
+              writeResource(env.getFiler(), originatingElement, proguardFile, proguardFileContents);
+            });
+    // Processing is over so this shouldn't matter, but clear the map just incase.
+    lazyMapKeysByModule.clear();
+  }
+
+  private void writeResource(
+      XFiler filer, XElement originatingElement, Path path, String contents) {
+    try (OutputStream outputStream =
+            filer.writeResource(path, ImmutableList.of(originatingElement), XFiler.Mode.Isolating);
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) {
+      writer.write(contents);
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /** Returns the fully qualified class name, with _ instead of . */
+  private static String getFullyQualifiedEnclosedClassName(ClassName className) {
+    return Joiner.on('_')
+        .join(
+            ImmutableList.<String>builder()
+                .add(className.packageName().replace('.', '_'))
+                .addAll(className.simpleNames())
+                .build());
+  }
+}
diff --git a/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java b/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
index 1df14ec..72e2064 100644
--- a/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
@@ -33,7 +33,6 @@
 import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.DelegateDeclaration;
 import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.validation.ModuleValidator;
 import dagger.internal.codegen.validation.ValidationReport;
@@ -51,7 +50,7 @@
   private final XMessager messager;
   private final ModuleValidator moduleValidator;
   private final BindingFactory bindingFactory;
-  private final SourceFileGenerator<ProvisionBinding> factoryGenerator;
+  private final SourceFileGenerator<ContributionBinding> factoryGenerator;
   private final SourceFileGenerator<ProductionBinding> producerFactoryGenerator;
   private final SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator;
   private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator;
@@ -63,7 +62,7 @@
       XMessager messager,
       ModuleValidator moduleValidator,
       BindingFactory bindingFactory,
-      SourceFileGenerator<ProvisionBinding> factoryGenerator,
+      SourceFileGenerator<ContributionBinding> factoryGenerator,
       SourceFileGenerator<ProductionBinding> producerFactoryGenerator,
       @ModuleGenerator SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator,
       InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator,
diff --git a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
index 3692144..362992b 100644
--- a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
+++ b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java
@@ -16,9 +16,11 @@
 
 package dagger.internal.codegen.processingstep;
 
+import static androidx.room.compiler.codegen.compat.XConverters.toJavaPoet;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
 import static dagger.internal.codegen.javapoet.TypeNames.PRODUCTION_COMPONENT_MONITOR_FACTORY;
 import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
 import static dagger.internal.codegen.javapoet.TypeNames.setOf;
@@ -31,12 +33,12 @@
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.TypeSpec;
 import dagger.Module;
 import dagger.internal.codegen.base.SourceFileGenerator;
 import dagger.internal.codegen.binding.MonitoringModules;
-import dagger.internal.codegen.binding.SourceFiles;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.multibindings.Multibinds;
 import javax.inject.Inject;
@@ -61,9 +63,10 @@
 
   @Override
   public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement componentElement) {
-    monitoringModules.add(SourceFiles.generatedMonitoringModuleName(componentElement));
+    ClassName name = toJavaPoet(generatedMonitoringModuleName(componentElement));
+    monitoringModules.add(name);
     return ImmutableList.of(
-        classBuilder(SourceFiles.generatedMonitoringModuleName(componentElement))
+        classBuilder(name)
             .addAnnotation(Module.class)
             .addModifiers(ABSTRACT)
             .addMethod(privateConstructor())
diff --git a/java/dagger/internal/codegen/processingstep/ProcessingStepsModule.java b/java/dagger/internal/codegen/processingstep/ProcessingStepsModule.java
index e24dddc..f180c3d 100644
--- a/java/dagger/internal/codegen/processingstep/ProcessingStepsModule.java
+++ b/java/dagger/internal/codegen/processingstep/ProcessingStepsModule.java
@@ -39,6 +39,7 @@
       MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep,
       BindsInstanceProcessingStep bindsInstanceProcessingStep,
       ModuleProcessingStep moduleProcessingStep,
+      LazyClassKeyProcessingStep lazyClassKeyProcessingStep,
       ComponentProcessingStep componentProcessingStep,
       ComponentHjarProcessingStep componentHjarProcessingStep,
       BindingMethodProcessingStep bindingMethodProcessingStep,
@@ -53,9 +54,8 @@
         multibindingAnnotationsProcessingStep,
         bindsInstanceProcessingStep,
         moduleProcessingStep,
-        compilerOptions.headerCompilation()
-            ? componentHjarProcessingStep
-            : componentProcessingStep,
+        lazyClassKeyProcessingStep,
+        compilerOptions.headerCompilation() ? componentHjarProcessingStep : componentProcessingStep,
         bindingMethodProcessingStep);
   }
 
diff --git a/java/dagger/internal/codegen/validation/BindingElementValidator.java b/java/dagger/internal/codegen/validation/BindingElementValidator.java
index c7c9f76..93f4f07 100644
--- a/java/dagger/internal/codegen/validation/BindingElementValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingElementValidator.java
@@ -42,6 +42,7 @@
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.model.Scope;
 import dagger.internal.codegen.xprocessing.XElements;
+import dagger.internal.codegen.xprocessing.XTypes;
 import java.util.Formatter;
 import java.util.HashMap;
 import java.util.Map;
@@ -144,7 +145,7 @@
       checkType();
       checkQualifiers();
       checkMapKeys();
-      checkMultibindings();
+      checkMultibindingAnnotations();
       checkScopes();
       checkAdditionalProperties();
       return report.build();
@@ -176,6 +177,9 @@
     protected void checkType() {
       switch (ContributionType.fromBindingElement(element)) {
         case UNIQUE:
+          // Basic checks on the types
+          bindingElementType().ifPresent(this::checkKeyType);
+
           // Validate that a unique binding is not attempting to bind a framework type. This
           // validation is only appropriate for unique bindings because multibindings may collect
           // framework types.  E.g. Set<Provider<Foo>> is perfectly reasonable.
@@ -185,15 +189,22 @@
           // This validation is only appropriate for unique bindings because multibindings may
           // collect assisted types.
           checkAssistedType();
-          // fall through
+
+          // Check for any specifically disallowed types
+          bindingElementType().ifPresent(this::checkDisallowedType);
+          break;
 
         case SET:
+          bindingElementType().ifPresent(this::checkSetValueFrameworkType);
+          break;
+
         case MAP:
-          bindingElementType().ifPresent(this::checkKeyType);
+          bindingElementType().ifPresent(this::checkMapValueFrameworkType);
           break;
 
         case SET_VALUES:
           checkSetValuesType();
+          break;
       }
     }
 
@@ -245,7 +256,7 @@
         if (setType.isRawType()) {
           report.addError(elementsIntoSetRawSetMessage());
         } else {
-          checkKeyType(setType.elementType());
+          checkSetValueFrameworkType(setType.elementType());
         }
       }
     }
@@ -301,7 +312,7 @@
      *       dagger.producers.Produces} annotation has a {@code type} parameter.
      * </ul>
      */
-    private void checkMultibindings() {
+    private void checkMultibindingAnnotations() {
       ImmutableSet<XAnnotation> multibindingAnnotations =
           XElements.getAllAnnotations(element, MULTIBINDING_ANNOTATIONS);
 
@@ -358,7 +369,37 @@
      */
     private void checkFrameworkType() {
       if (bindingElementType().filter(FrameworkTypes::isFrameworkType).isPresent()) {
-        report.addError(bindingElements("must not %s framework types", bindingElementTypeVerb()));
+        report.addError(bindingElements("must not %s framework types: %s",
+            bindingElementTypeVerb(), XTypes.toStableString(bindingElementType().get())));
+      }
+    }
+
+    private void checkSetValueFrameworkType(XType bindingType) {
+      checkKeyType(bindingType);
+      if (FrameworkTypes.isSetValueFrameworkType(bindingType)) {
+        report.addError(bindingElements(
+            "with @IntoSet/@ElementsIntoSet must not %s framework types: %s",
+            bindingElementTypeVerb(), XTypes.toStableString(bindingType)));
+      }
+      checkDisallowedType(bindingType);
+    }
+
+    private void checkMapValueFrameworkType(XType bindingType) {
+      checkKeyType(bindingType);
+      if (FrameworkTypes.isMapValueFrameworkType(bindingType)) {
+        report.addError(
+            bindingElements("with @IntoMap must not %s framework types: %s",
+                bindingElementTypeVerb(), XTypes.toStableString(bindingType)));
+      }
+      checkDisallowedType(bindingType);
+    }
+
+    private void checkDisallowedType(XType bindingType) {
+      // TODO(erichang): Consider if we want to go inside complex types to ban
+      // dagger.internal.Provider as well? E.g. List<dagger.internal.Provider<Foo>>
+      if (FrameworkTypes.isDisallowedType(bindingType)) {
+        report.addError(bindingElements("must not %s disallowed types: %s",
+            bindingElementTypeVerb(), XTypes.toStableString(bindingElementType().get())));
       }
     }
   }
diff --git a/java/dagger/internal/codegen/validation/BindsMethodValidator.java b/java/dagger/internal/codegen/validation/BindsMethodValidator.java
index c3ad90a..1af35ce 100644
--- a/java/dagger/internal/codegen/validation/BindsMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/BindsMethodValidator.java
@@ -33,6 +33,7 @@
 import dagger.internal.codegen.binding.BindsTypeChecker;
 import dagger.internal.codegen.binding.InjectionAnnotations;
 import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.xprocessing.Nullability;
 import javax.inject.Inject;
 
 /** A validator for {@link dagger.Binds} methods. */
@@ -45,7 +46,6 @@
       BindsTypeChecker bindsTypeChecker,
       DaggerSuperficialValidation superficialValidation,
       XProcessingEnv processingEnv,
-
       DependencyRequestValidator dependencyRequestValidator,
       InjectionAnnotations injectionAnnotations) {
     super(
@@ -110,6 +110,12 @@
         // Set.addAll(Collection<? extends E>)
         report.addError("@Binds methods' parameter type must be assignable to the return type");
       }
+
+      Nullability parameterNullability = Nullability.of(parameter);
+      Nullability methodNullability = Nullability.of(method);
+      if (parameterNullability.isNullable() != methodNullability.isNullable()) {
+        report.addError("@Binds methods' nullability must match the nullability of its parameter");
+      }
     }
 
     private XType boxIfNecessary(XType maybePrimitive) {
diff --git a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
index 5510048..87bcad0 100644
--- a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
+++ b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
@@ -18,7 +18,9 @@
 
 import static androidx.room.compiler.processing.XElementKt.isField;
 import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.base.FrameworkTypes.isDisallowedType;
 import static dagger.internal.codegen.base.FrameworkTypes.isFrameworkType;
+import static dagger.internal.codegen.base.FrameworkTypes.isMapValueFrameworkType;
 import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedInjectionType;
@@ -40,6 +42,7 @@
 import androidx.room.compiler.processing.XVariableElement;
 import com.google.common.collect.ImmutableSet;
 import dagger.internal.codegen.base.FrameworkTypes;
+import dagger.internal.codegen.base.MapType;
 import dagger.internal.codegen.base.RequestKinds;
 import dagger.internal.codegen.binding.InjectionAnnotations;
 import dagger.internal.codegen.javapoet.TypeNames;
@@ -154,6 +157,14 @@
         // will just be noise.
         return;
       }
+      if (isDisallowedType(requestType)) {
+        report.addError(
+            "Dagger disallows injecting the type: " + XTypes.toStableString(requestType),
+            requestElement);
+        // If the requested type is a disallowed type then skip the remaining checks as they
+        // will just be noise.
+        return;
+      }
       XType keyType = extractKeyType(requestType);
       if (qualifiers.isEmpty() && isDeclared(keyType)) {
         XTypeElement typeElement = keyType.getTypeElement();
@@ -191,6 +202,24 @@
                   requestElement, keyType.getTypeArguments().get(0)));
         }
       }
+      if (MapType.isMap(keyType)) {
+        MapType mapType = MapType.from(keyType);
+        if (!mapType.isRawType()) {
+          XType valueType = mapType.valueType();
+          if (isMapValueFrameworkType(valueType) && isRawParameterizedType(valueType)) {
+            report.addError(
+                "Dagger does not support injecting maps of raw framework types: "
+                + XTypes.toStableString(requestType),
+                requestElement);
+          }
+          if (isDisallowedType(valueType)) {
+            report.addError(
+                "Dagger does not support injecting maps of disallowed types: "
+                + XTypes.toStableString(requestType),
+                requestElement);
+          }
+        }
+      }
     }
   }
 
diff --git a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
index 24ad676..3f63d25 100644
--- a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
+++ b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
@@ -165,9 +165,9 @@
       ImmutableSet<DependencyEdge> requests,
       ImmutableSet<DependencyEdge> entryPoints) {
     StringBuilder message = new StringBuilder(dependencyTrace.size() * 100 /* a guess heuristic */);
-    dependencyTrace.forEach(
-        edge -> dependencyRequestFormatter.appendFormatLine(message, edge.dependencyRequest()));
+    message.append("\n");
     if (!dependencyTrace.isEmpty()) {
+      message.append(dependencyRequestFormatter.formatEdges(dependencyTrace, graph));
       appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace)));
     }
     message.append(getRequestsNotInTrace(dependencyTrace, requests, entryPoints));
@@ -257,7 +257,7 @@
   // TODO(ronshapiro): Adding a DependencyPath type to dagger.internal.codegen.model could be
   // useful, i.e.
   // bindingGraph.shortestPathFromEntryPoint(DependencyEdge, MaybeBindingNode)
-  public ImmutableList<DependencyEdge> dependencyTrace(
+  private ImmutableList<DependencyEdge> dependencyTrace(
       MaybeBinding binding, ImmutableSet<DependencyEdge> entryPoints) {
     // Module binding graphs may have bindings unreachable from any entry points. If there are
     // no entry points for this DiagnosticInfo, don't try to print a dependency trace.
diff --git a/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
index ba8e6a0..c11457c 100644
--- a/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
+++ b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
@@ -84,6 +84,10 @@
     plugin.init(SpiModelBindingGraphConverter.toSpiModel(processingEnv), filteredOptions);
   }
 
+  public void onProcessingRoundBegin() {
+    plugins.forEach(BindingGraphPlugin::onProcessingRoundBegin);
+  }
+
   private void initializeLegacyPlugin(dagger.spi.BindingGraphPlugin plugin) {
     plugin.initFiler(toJavac(filer));
     plugin.initTypes(toJavac(processingEnv).getTypeUtils()); // ALLOW_TYPES_ELEMENTS
diff --git a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
index 16344d3..ab2a571 100644
--- a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
+++ b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
@@ -24,6 +24,7 @@
 import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
 import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
+import static dagger.internal.codegen.binding.InjectionAnnotations.hasInjectAnnotation;
 import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
@@ -50,12 +51,15 @@
 import dagger.Provides;
 import dagger.internal.codegen.base.SourceFileGenerationException;
 import dagger.internal.codegen.base.SourceFileGenerator;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingFactory;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.InjectBindingRegistry;
+import dagger.internal.codegen.binding.InjectionBinding;
 import dagger.internal.codegen.binding.KeyFactory;
 import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.MembersInjectorBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.Key;
@@ -80,7 +84,6 @@
   private final XProcessingEnv processingEnv;
   private final XMessager messager;
   private final InjectValidator injectValidator;
-  private final InjectValidator injectValidatorWhenGeneratingCode;
   private final KeyFactory keyFactory;
   private final BindingFactory bindingFactory;
   private final CompilerOptions compilerOptions;
@@ -102,7 +105,7 @@
         checkState(!binding.unresolved().isPresent());
         XType type = binding.key().type().xprocessing();
         if (!isDeclared(type)
-            || injectValidatorWhenGeneratingCode.validate(type.getTypeElement()).isClean()) {
+                || injectValidator.validateWhenGeneratingCode(type.getTypeElement()).isClean()) {
           generator.generate(binding);
         }
         materializedBindingKeys.add(binding.key());
@@ -203,7 +206,7 @@
     }
   }
 
-  private final BindingsCollection<ProvisionBinding> provisionBindings =
+  private final BindingsCollection<ContributionBinding> injectionBindings =
       new BindingsCollection<>(TypeNames.PROVIDER);
   private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
       new BindingsCollection<>(TypeNames.MEMBERS_INJECTOR);
@@ -219,7 +222,6 @@
     this.processingEnv = processingEnv;
     this.messager = messager;
     this.injectValidator = injectValidator;
-    this.injectValidatorWhenGeneratingCode = injectValidator.whenGeneratingCode();
     this.keyFactory = keyFactory;
     this.bindingFactory = bindingFactory;
     this.compilerOptions = compilerOptions;
@@ -228,15 +230,15 @@
   // TODO(dpb): make the SourceFileGenerators fields so they don't have to be passed in
   @Override
   public void generateSourcesForRequiredBindings(
-      SourceFileGenerator<ProvisionBinding> factoryGenerator,
+      SourceFileGenerator<ContributionBinding> factoryGenerator,
       SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
       throws SourceFileGenerationException {
-    provisionBindings.generateBindings(factoryGenerator);
+    injectionBindings.generateBindings(factoryGenerator);
     membersInjectionBindings.generateBindings(membersInjectorGenerator);
   }
 
   @Override
-  public Optional<ProvisionBinding> tryRegisterInjectConstructor(
+  public Optional<ContributionBinding> tryRegisterInjectConstructor(
       XConstructorElement constructorElement) {
     return tryRegisterConstructor(
         constructorElement,
@@ -245,7 +247,7 @@
   }
 
   @CanIgnoreReturnValue
-  private Optional<ProvisionBinding> tryRegisterConstructor(
+  private Optional<ContributionBinding> tryRegisterConstructor(
       XConstructorElement constructorElement,
       Optional<XType> resolvedType,
       boolean isCalledFromInjectProcessor) {
@@ -260,17 +262,30 @@
 
     XType type = typeElement.getType();
     Key key = keyFactory.forInjectConstructorWithResolvedType(type);
-    ProvisionBinding cachedBinding = provisionBindings.getBinding(key);
+    ContributionBinding cachedBinding = injectionBindings.getBinding(key);
     if (cachedBinding != null) {
       return Optional.of(cachedBinding);
     }
 
-    ProvisionBinding binding = bindingFactory.injectionBinding(constructorElement, resolvedType);
-    provisionBindings.tryRegisterBinding(binding, isCalledFromInjectProcessor);
-    if (!binding.injectionSites().isEmpty()) {
-      tryRegisterMembersInjectedType(typeElement, resolvedType, isCalledFromInjectProcessor);
+    if (hasInjectAnnotation(constructorElement)) {
+      InjectionBinding binding = bindingFactory.injectionBinding(constructorElement, resolvedType);
+      injectionBindings.tryRegisterBinding(binding, isCalledFromInjectProcessor);
+      if (!binding.injectionSites().isEmpty()) {
+        tryRegisterMembersInjectedType(typeElement, resolvedType, isCalledFromInjectProcessor);
+      }
+      return Optional.of(binding);
+    } else if (constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)) {
+      AssistedInjectionBinding binding =
+          bindingFactory.assistedInjectionBinding(constructorElement, resolvedType);
+      injectionBindings.tryRegisterBinding(binding, isCalledFromInjectProcessor);
+      if (!binding.injectionSites().isEmpty()) {
+        tryRegisterMembersInjectedType(typeElement, resolvedType, isCalledFromInjectProcessor);
+      }
+      return Optional.of(binding);
     }
-    return Optional.of(binding);
+    throw new AssertionError(
+        "Expected either an @Inject or @AssistedInject annotated constructor: "
+            + constructorElement.getEnclosingElement().getQualifiedName());
   }
 
   @Override
@@ -336,12 +351,12 @@
 
   @CanIgnoreReturnValue
   @Override
-  public Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
+  public Optional<ContributionBinding> getOrFindInjectionBinding(Key key) {
     checkNotNull(key);
     if (!isValidImplicitProvisionKey(key)) {
       return Optional.empty();
     }
-    ProvisionBinding binding = provisionBindings.getBinding(key);
+    ContributionBinding binding = injectionBindings.getBinding(key);
     if (binding != null) {
       return Optional.of(binding);
     }
@@ -385,7 +400,7 @@
   }
 
   @Override
-  public Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key) {
+  public Optional<MembersInjectorBinding> getOrFindMembersInjectorBinding(Key key) {
     if (!isValidMembersInjectionKey(key)) {
       return Optional.empty();
     }
diff --git a/java/dagger/internal/codegen/validation/InjectValidator.java b/java/dagger/internal/codegen/validation/InjectValidator.java
index ac434d7..135839d 100644
--- a/java/dagger/internal/codegen/validation/InjectValidator.java
+++ b/java/dagger/internal/codegen/validation/InjectValidator.java
@@ -56,7 +56,6 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.tools.Diagnostic;
-import javax.tools.Diagnostic.Kind;
 
 /**
  * A {@linkplain ValidationReport validator} for {@link Inject}-annotated elements and the types
@@ -66,14 +65,12 @@
 public final class InjectValidator implements ClearableCache {
 
   private final XProcessingEnv processingEnv;
-  private final CompilerOptions compilerOptions;
   private final DependencyRequestValidator dependencyRequestValidator;
-  private final Optional<Diagnostic.Kind> privateAndStaticInjectionDiagnosticKind;
   private final InjectionAnnotations injectionAnnotations;
   private final DaggerSuperficialValidation superficialValidation;
-  private final Map<XTypeElement, ValidationReport> provisionReports = new HashMap<>();
-  private final Map<XTypeElement, ValidationReport> membersInjectionReports = new HashMap<>();
   private final MethodSignatureFormatter methodSignatureFormatter;
+  private final InternalValidator validator;
+  private final InternalValidator validatorWhenGeneratingCode;
 
   @Inject
   InjectValidator(
@@ -83,378 +80,390 @@
       InjectionAnnotations injectionAnnotations,
       DaggerSuperficialValidation superficialValidation,
       MethodSignatureFormatter methodSignatureFormatter) {
-    this(
-        processingEnv,
-        compilerOptions,
-        dependencyRequestValidator,
-        Optional.empty(),
-        injectionAnnotations,
-        superficialValidation,
-        methodSignatureFormatter);
-  }
-
-  private InjectValidator(
-      XProcessingEnv processingEnv,
-      CompilerOptions compilerOptions,
-      DependencyRequestValidator dependencyRequestValidator,
-      Optional<Kind> privateAndStaticInjectionDiagnosticKind,
-      InjectionAnnotations injectionAnnotations,
-      DaggerSuperficialValidation superficialValidation,
-      MethodSignatureFormatter methodSignatureFormatter) {
     this.processingEnv = processingEnv;
-    this.compilerOptions = compilerOptions;
     this.dependencyRequestValidator = dependencyRequestValidator;
-    this.privateAndStaticInjectionDiagnosticKind = privateAndStaticInjectionDiagnosticKind;
     this.injectionAnnotations = injectionAnnotations;
     this.superficialValidation = superficialValidation;
     this.methodSignatureFormatter = methodSignatureFormatter;
+
+    // When validating types that require a generated factory class we need to error on private and
+    // static inject members even if the compiler options are set to not error.
+    this.validatorWhenGeneratingCode =
+        new InternalValidator(Diagnostic.Kind.ERROR, Diagnostic.Kind.ERROR);
+
+    // When validating types that might not require a generated factory we can take the user flags
+    // for private and static inject members into account, but try to reuse the existing one if the
+    // diagnostic kinds are the same.
+    this.validator =
+        (compilerOptions.privateMemberValidationKind() == Diagnostic.Kind.ERROR
+                && compilerOptions.staticMemberValidationKind() == Diagnostic.Kind.ERROR)
+            ? validatorWhenGeneratingCode
+            : new InternalValidator(
+                compilerOptions.privateMemberValidationKind(),
+                compilerOptions.staticMemberValidationKind());
   }
 
   @Override
   public void clearCache() {
-    provisionReports.clear();
-    membersInjectionReports.clear();
-  }
-
-  /**
-   * Returns a new validator that performs the same validation as this one, but is strict about
-   * rejecting optionally-specified JSR 330 behavior that Dagger doesn't support (unless {@code
-   * -Adagger.ignorePrivateAndStaticInjectionForComponent=enabled} was set in the javac options).
-   */
-  public InjectValidator whenGeneratingCode() {
-    return compilerOptions.ignorePrivateAndStaticInjectionForComponent()
-        ? this
-        : new InjectValidator(
-            processingEnv,
-            compilerOptions,
-            dependencyRequestValidator,
-            Optional.of(Diagnostic.Kind.ERROR),
-            injectionAnnotations,
-            superficialValidation,
-            methodSignatureFormatter);
+    validator.clearCache();
+    validatorWhenGeneratingCode.clearCache();
   }
 
   public ValidationReport validate(XTypeElement typeElement) {
-    return reentrantComputeIfAbsent(provisionReports, typeElement, this::validateUncached);
-  }
-
-  private ValidationReport validateUncached(XTypeElement typeElement) {
-    ValidationReport.Builder builder = ValidationReport.about(typeElement);
-    builder.addSubreport(validateForMembersInjectionInternal(typeElement));
-
-    ImmutableSet<XConstructorElement> injectConstructors =
-        ImmutableSet.<XConstructorElement>builder()
-            .addAll(injectedConstructors(typeElement))
-            .addAll(assistedInjectedConstructors(typeElement))
-            .build();
-
-    switch (injectConstructors.size()) {
-      case 0:
-        break; // Nothing to validate.
-      case 1:
-        builder.addSubreport(validateConstructor(getOnlyElement(injectConstructors)));
-        break;
-      default:
-        builder.addError(
-            String.format(
-                "Type %s may only contain one injected constructor. Found: %s",
-                typeElement.getQualifiedName(),
-                injectConstructors.stream()
-                    .map(methodSignatureFormatter::format)
-                    .collect(toImmutableList())),
-            typeElement);
-    }
-
-    return builder.build();
-  }
-
-  private ValidationReport validateConstructor(XConstructorElement constructorElement) {
-    superficialValidation.validateTypeOf(constructorElement);
-    ValidationReport.Builder builder =
-        ValidationReport.about(constructorElement.getEnclosingElement());
-
-    if (InjectionAnnotations.hasInjectAnnotation(constructorElement)
-        && constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)) {
-      builder.addError("Constructors cannot be annotated with both @Inject and @AssistedInject");
-    }
-
-    ClassName injectAnnotation =
-        getAnyAnnotation(
-                constructorElement,
-                TypeNames.INJECT,
-                TypeNames.INJECT_JAVAX,
-                TypeNames.ASSISTED_INJECT)
-            .map(XAnnotations::getClassName)
-            .get();
-
-    if (constructorElement.isPrivate()) {
-      builder.addError(
-          "Dagger does not support injection into private constructors", constructorElement);
-    }
-
-    // If this type has already been processed in a previous round or compilation unit then there
-    // is no reason to recheck for invalid scope annotations since it's already been checked.
-    // This allows us to skip superficial validation of constructor annotations in subsequent
-    // compilations where the annotation types may no longer be on the classpath.
-    if (!processedInPreviousRoundOrCompilationUnit(constructorElement)) {
-      superficialValidation.validateAnnotationsOf(constructorElement);
-      for (XAnnotation qualifier : injectionAnnotations.getQualifiers(constructorElement)) {
-        builder.addError(
-            String.format(
-                "@Qualifier annotations are not allowed on @%s constructors",
-                injectAnnotation.simpleName()),
-            constructorElement,
-            qualifier);
-      }
-
-      String scopeErrorMsg =
-          String.format(
-              "@Scope annotations are not allowed on @%s constructors",
-              injectAnnotation.simpleName());
-
-      if (injectAnnotation.equals(TypeNames.INJECT)
-          || injectAnnotation.equals(TypeNames.INJECT_JAVAX)) {
-        scopeErrorMsg += "; annotate the class instead";
-      }
-
-      for (Scope scope : injectionAnnotations.getScopes(constructorElement)) {
-        builder.addError(scopeErrorMsg, constructorElement, scope.scopeAnnotation().xprocessing());
-      }
-    }
-
-    for (XExecutableParameterElement parameter : constructorElement.getParameters()) {
-      superficialValidation.validateTypeOf(parameter);
-      validateDependencyRequest(builder, parameter);
-    }
-
-    if (throwsCheckedExceptions(constructorElement)) {
-      builder.addItem(
-          String.format(
-              "Dagger does not support checked exceptions on @%s constructors",
-              injectAnnotation.simpleName()),
-          privateMemberDiagnosticKind(),
-          constructorElement);
-    }
-
-    checkInjectIntoPrivateClass(constructorElement, builder);
-
-    XTypeElement enclosingElement = constructorElement.getEnclosingElement();
-    if (enclosingElement.isAbstract()) {
-      builder.addError(
-          String.format(
-              "@%s is nonsense on the constructor of an abstract class",
-              injectAnnotation.simpleName()),
-          constructorElement);
-    }
-
-    if (enclosingElement.isNested() && !enclosingElement.isStatic()) {
-      builder.addError(
-          String.format(
-              "@%s constructors are invalid on inner classes. "
-                  + "Did you mean to make the class static?",
-              injectAnnotation.simpleName()),
-          constructorElement);
-    }
-
-    // Note: superficial validation of the annotations is done as part of getting the scopes.
-    ImmutableSet<Scope> scopes =
-        injectionAnnotations.getScopes(constructorElement.getEnclosingElement());
-    if (injectAnnotation.equals(TypeNames.ASSISTED_INJECT)) {
-      for (Scope scope : scopes) {
-        builder.addError(
-            "A type with an @AssistedInject-annotated constructor cannot be scoped",
-            enclosingElement,
-            scope.scopeAnnotation().xprocessing());
-      }
-    } else if (scopes.size() > 1) {
-      for (Scope scope : scopes) {
-        builder.addError(
-            "A single binding may not declare more than one @Scope",
-            enclosingElement,
-            scope.scopeAnnotation().xprocessing());
-      }
-    }
-
-    return builder.build();
-  }
-
-  private ValidationReport validateField(XFieldElement fieldElement) {
-    superficialValidation.validateTypeOf(fieldElement);
-    ValidationReport.Builder builder = ValidationReport.about(fieldElement);
-    if (fieldElement.isFinal()) {
-      builder.addError("@Inject fields may not be final", fieldElement);
-    }
-
-    if (fieldElement.isPrivate()) {
-      builder.addItem(
-          "Dagger does not support injection into private fields",
-          privateMemberDiagnosticKind(),
-          fieldElement);
-    }
-
-    if (fieldElement.isStatic()) {
-      builder.addItem(
-          "Dagger does not support injection into static fields",
-          staticMemberDiagnosticKind(),
-          fieldElement);
-    }
-
-    if (fieldElement.isProtected()
-        && fieldElement.getEnclosingElement().isFromKotlin()
-        ) {
-      builder.addItem(
-          "Dagger injector does not have access to kotlin protected fields",
-          staticMemberDiagnosticKind(),
-          fieldElement);
-    }
-
-    validateDependencyRequest(builder, fieldElement);
-
-    return builder.build();
-  }
-
-  private ValidationReport validateMethod(XMethodElement methodElement) {
-    superficialValidation.validateTypeOf(methodElement);
-    ValidationReport.Builder builder = ValidationReport.about(methodElement);
-    if (methodElement.isAbstract()) {
-      builder.addError("Methods with @Inject may not be abstract", methodElement);
-    }
-
-    if (methodElement.isPrivate()) {
-      builder.addItem(
-          "Dagger does not support injection into private methods",
-          privateMemberDiagnosticKind(),
-          methodElement);
-    }
-
-    if (methodElement.isStatic()) {
-      builder.addItem(
-          "Dagger does not support injection into static methods",
-          staticMemberDiagnosticKind(),
-          methodElement);
-    }
-
-    // No need to resolve type parameters since we're only checking existence.
-    if (hasTypeParameters(methodElement)) {
-      builder.addError("Methods with @Inject may not declare type parameters", methodElement);
-    }
-
-    // No need to resolve thrown types since we're only checking existence.
-    if (!methodElement.getThrownTypes().isEmpty()) {
-      builder.addError(
-          "Methods with @Inject may not throw checked exceptions. "
-              + "Please wrap your exceptions in a RuntimeException instead.",
-          methodElement);
-    }
-
-    for (XExecutableParameterElement parameter : methodElement.getParameters()) {
-      superficialValidation.validateTypeOf(parameter);
-      validateDependencyRequest(builder, parameter);
-    }
-
-    return builder.build();
-  }
-
-  private void validateDependencyRequest(
-      ValidationReport.Builder builder, XVariableElement parameter) {
-    dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.getType());
-    dependencyRequestValidator.checkNotProducer(builder, parameter);
+    return validator.validate(typeElement);
   }
 
   public ValidationReport validateForMembersInjection(XTypeElement typeElement) {
-    return !processedInPreviousRoundOrCompilationUnit(typeElement)
-        ? validate(typeElement) // validate everything
-        : validateForMembersInjectionInternal(typeElement); // validate only inject members
+    return validator.validateForMembersInjection(typeElement);
   }
 
-  private ValidationReport validateForMembersInjectionInternal(XTypeElement typeElement) {
-    return reentrantComputeIfAbsent(
-        membersInjectionReports, typeElement, this::validateForMembersInjectionInternalUncached);
+  /**
+   * Validates {@code typeElement} that requires a factory to be generated.
+   *
+   * <p>In this case, the validator will have stricter validation for private and static injection
+   * since the generated factory doesn't support those types.
+   */
+  public ValidationReport validateWhenGeneratingCode(XTypeElement typeElement) {
+    if (typeElement.getPackageName().startsWith("org.atinject.tck")) {
+      // The Technology Compatibility Kit (TCK) package is a special package for testing the JSR330
+      // spec, which includes optional features like supporting static/private inject members. Even
+      // though Dagger doesn't support this, we allow it for this one case for the test coverage
+      // purposes. Use the normal validator which takes the user's compiler flags into account.
+      return validator.validate(typeElement);
+    }
+    return validatorWhenGeneratingCode.validate(typeElement);
   }
 
-  private ValidationReport validateForMembersInjectionInternalUncached(XTypeElement typeElement) {
-    superficialValidation.validateTypeOf(typeElement);
-    // TODO(beder): This element might not be currently compiled, so this error message could be
-    // left in limbo. Find an appropriate way to display the error message in that case.
-    ValidationReport.Builder builder = ValidationReport.about(typeElement);
-    boolean hasInjectedMembers = false;
-    for (XFieldElement field : typeElement.getDeclaredFields()) {
-      if (InjectionAnnotations.hasInjectAnnotation(field)) {
-        hasInjectedMembers = true;
-        ValidationReport report = validateField(field);
-        if (!report.isClean()) {
-          builder.addSubreport(report);
+  private final class InternalValidator {
+    private final Diagnostic.Kind privateMemberDiagnosticKind;
+    private final Diagnostic.Kind staticMemberDiagnosticKind;
+    private final Map<XTypeElement, ValidationReport> provisionReports = new HashMap<>();
+    private final Map<XTypeElement, ValidationReport> membersInjectionReports = new HashMap<>();
+
+    InternalValidator(
+        Diagnostic.Kind privateMemberDiagnosticKind, Diagnostic.Kind staticMemberDiagnosticKind) {
+      this.privateMemberDiagnosticKind = privateMemberDiagnosticKind;
+      this.staticMemberDiagnosticKind = staticMemberDiagnosticKind;
+    }
+
+    void clearCache() {
+      provisionReports.clear();
+      membersInjectionReports.clear();
+    }
+
+    ValidationReport validate(XTypeElement typeElement) {
+      return reentrantComputeIfAbsent(provisionReports, typeElement, this::validateUncached);
+    }
+
+    private ValidationReport validateUncached(XTypeElement typeElement) {
+      ValidationReport.Builder builder = ValidationReport.about(typeElement);
+      builder.addSubreport(validateForMembersInjectionInternal(typeElement));
+
+      ImmutableSet<XConstructorElement> injectConstructors =
+          ImmutableSet.<XConstructorElement>builder()
+              .addAll(injectedConstructors(typeElement))
+              .addAll(assistedInjectedConstructors(typeElement))
+              .build();
+
+      switch (injectConstructors.size()) {
+        case 0:
+          break; // Nothing to validate.
+        case 1:
+          builder.addSubreport(validateConstructor(getOnlyElement(injectConstructors)));
+          break;
+        default:
+          builder.addError(
+              String.format(
+                  "Type %s may only contain one injected constructor. Found: %s",
+                  typeElement.getQualifiedName(),
+                  injectConstructors.stream()
+                      .map(methodSignatureFormatter::format)
+                      .collect(toImmutableList())),
+              typeElement);
+      }
+
+      return builder.build();
+    }
+
+    private ValidationReport validateConstructor(XConstructorElement constructorElement) {
+      superficialValidation.validateTypeOf(constructorElement);
+      ValidationReport.Builder builder =
+          ValidationReport.about(constructorElement.getEnclosingElement());
+
+      if (InjectionAnnotations.hasInjectAnnotation(constructorElement)
+          && constructorElement.hasAnnotation(TypeNames.ASSISTED_INJECT)) {
+        builder.addError("Constructors cannot be annotated with both @Inject and @AssistedInject");
+      }
+
+      ClassName injectAnnotation =
+          getAnyAnnotation(
+                  constructorElement,
+                  TypeNames.INJECT,
+                  TypeNames.INJECT_JAVAX,
+                  TypeNames.ASSISTED_INJECT)
+              .map(XAnnotations::getClassName)
+              .get();
+
+      if (constructorElement.isPrivate()) {
+        builder.addError(
+            "Dagger does not support injection into private constructors", constructorElement);
+      }
+
+      // If this type has already been processed in a previous round or compilation unit then there
+      // is no reason to recheck for invalid scope annotations since it's already been checked.
+      // This allows us to skip superficial validation of constructor annotations in subsequent
+      // compilations where the annotation types may no longer be on the classpath.
+      if (!processedInPreviousRoundOrCompilationUnit(constructorElement)) {
+        superficialValidation.validateAnnotationsOf(constructorElement);
+        for (XAnnotation qualifier : injectionAnnotations.getQualifiers(constructorElement)) {
+          builder.addError(
+              String.format(
+                  "@Qualifier annotations are not allowed on @%s constructors",
+                  injectAnnotation.simpleName()),
+              constructorElement,
+              qualifier);
+        }
+
+        String scopeErrorMsg =
+            String.format(
+                "@Scope annotations are not allowed on @%s constructors",
+                injectAnnotation.simpleName());
+
+        if (injectAnnotation.equals(TypeNames.INJECT)
+            || injectAnnotation.equals(TypeNames.INJECT_JAVAX)) {
+          scopeErrorMsg += "; annotate the class instead";
+        }
+
+        for (Scope scope : injectionAnnotations.getScopes(constructorElement)) {
+          builder.addError(
+              scopeErrorMsg, constructorElement, scope.scopeAnnotation().xprocessing());
         }
       }
-    }
-    for (XMethodElement method : typeElement.getDeclaredMethods()) {
-      if (InjectionAnnotations.hasInjectAnnotation(method)) {
-        hasInjectedMembers = true;
-        ValidationReport report = validateMethod(method);
-        if (!report.isClean()) {
-          builder.addSubreport(report);
+
+      for (XExecutableParameterElement parameter : constructorElement.getParameters()) {
+        superficialValidation.validateTypeOf(parameter);
+        validateDependencyRequest(builder, parameter);
+      }
+
+      if (throwsCheckedExceptions(constructorElement)) {
+        builder.addItem(
+            String.format(
+                "Dagger does not support checked exceptions on @%s constructors",
+                injectAnnotation.simpleName()),
+            privateMemberDiagnosticKind,
+            constructorElement);
+      }
+
+      checkInjectIntoPrivateClass(constructorElement, builder);
+
+      XTypeElement enclosingElement = constructorElement.getEnclosingElement();
+      if (enclosingElement.isAbstract()) {
+        builder.addError(
+            String.format(
+                "@%s is nonsense on the constructor of an abstract class",
+                injectAnnotation.simpleName()),
+            constructorElement);
+      }
+
+      if (enclosingElement.isNested() && !enclosingElement.isStatic()) {
+        builder.addError(
+            String.format(
+                "@%s constructors are invalid on inner classes. "
+                    + "Did you mean to make the class static?",
+                injectAnnotation.simpleName()),
+            constructorElement);
+      }
+
+      // Note: superficial validation of the annotations is done as part of getting the scopes.
+      ImmutableSet<Scope> scopes =
+          injectionAnnotations.getScopes(constructorElement.getEnclosingElement());
+      if (injectAnnotation.equals(TypeNames.ASSISTED_INJECT)) {
+        for (Scope scope : scopes) {
+          builder.addError(
+              "A type with an @AssistedInject-annotated constructor cannot be scoped",
+              enclosingElement,
+              scope.scopeAnnotation().xprocessing());
         }
+      } else if (scopes.size() > 1) {
+        for (Scope scope : scopes) {
+          builder.addError(
+              "A single binding may not declare more than one @Scope",
+              enclosingElement,
+              scope.scopeAnnotation().xprocessing());
+        }
+      }
+
+      return builder.build();
+    }
+
+    private ValidationReport validateField(XFieldElement fieldElement) {
+      superficialValidation.validateTypeOf(fieldElement);
+      ValidationReport.Builder builder = ValidationReport.about(fieldElement);
+      if (fieldElement.isFinal()) {
+        builder.addError("@Inject fields may not be final", fieldElement);
+      }
+
+      if (fieldElement.isPrivate()) {
+        builder.addItem(
+            "Dagger does not support injection into private fields",
+            privateMemberDiagnosticKind,
+            fieldElement);
+      }
+
+      if (fieldElement.isStatic()) {
+        builder.addItem(
+            "Dagger does not support injection into static fields",
+            staticMemberDiagnosticKind,
+            fieldElement);
+      }
+
+      if (fieldElement.isProtected()
+          && fieldElement.getEnclosingElement().isFromKotlin()
+          ) {
+        builder.addError(
+            "Dagger injector does not have access to kotlin protected fields", fieldElement);
+      }
+
+      validateDependencyRequest(builder, fieldElement);
+
+      return builder.build();
+    }
+
+    private ValidationReport validateMethod(XMethodElement methodElement) {
+      superficialValidation.validateTypeOf(methodElement);
+      ValidationReport.Builder builder = ValidationReport.about(methodElement);
+      if (methodElement.isAbstract()) {
+        builder.addError("Methods with @Inject may not be abstract", methodElement);
+      }
+
+      if (methodElement.isPrivate()) {
+        builder.addItem(
+            "Dagger does not support injection into private methods",
+            privateMemberDiagnosticKind,
+            methodElement);
+      }
+
+      if (methodElement.isStatic()) {
+        builder.addItem(
+            "Dagger does not support injection into static methods",
+            staticMemberDiagnosticKind,
+            methodElement);
+      }
+
+      // No need to resolve type parameters since we're only checking existence.
+      if (hasTypeParameters(methodElement)) {
+        builder.addError("Methods with @Inject may not declare type parameters", methodElement);
+      }
+
+      // No need to resolve thrown types since we're only checking existence.
+      if (!methodElement.getThrownTypes().isEmpty()) {
+        builder.addError(
+            "Methods with @Inject may not throw checked exceptions. "
+                + "Please wrap your exceptions in a RuntimeException instead.",
+            methodElement);
+      }
+
+      for (XExecutableParameterElement parameter : methodElement.getParameters()) {
+        superficialValidation.validateTypeOf(parameter);
+        validateDependencyRequest(builder, parameter);
+      }
+
+      return builder.build();
+    }
+
+    private void validateDependencyRequest(
+        ValidationReport.Builder builder, XVariableElement parameter) {
+      dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.getType());
+      dependencyRequestValidator.checkNotProducer(builder, parameter);
+    }
+
+    public ValidationReport validateForMembersInjection(XTypeElement typeElement) {
+      return !processedInPreviousRoundOrCompilationUnit(typeElement)
+          ? validate(typeElement) // validate everything
+          : validateForMembersInjectionInternal(typeElement); // validate only inject members
+    }
+
+    private ValidationReport validateForMembersInjectionInternal(XTypeElement typeElement) {
+      return reentrantComputeIfAbsent(
+          membersInjectionReports, typeElement, this::validateForMembersInjectionInternalUncached);
+    }
+
+    private ValidationReport validateForMembersInjectionInternalUncached(XTypeElement typeElement) {
+      superficialValidation.validateTypeOf(typeElement);
+      // TODO(beder): This element might not be currently compiled, so this error message could be
+      // left in limbo. Find an appropriate way to display the error message in that case.
+      ValidationReport.Builder builder = ValidationReport.about(typeElement);
+      boolean hasInjectedMembers = false;
+      for (XFieldElement field : typeElement.getDeclaredFields()) {
+        if (InjectionAnnotations.hasInjectAnnotation(field)) {
+          hasInjectedMembers = true;
+          ValidationReport report = validateField(field);
+          if (!report.isClean()) {
+            builder.addSubreport(report);
+          }
+        }
+      }
+      for (XMethodElement method : typeElement.getDeclaredMethods()) {
+        if (InjectionAnnotations.hasInjectAnnotation(method)) {
+          hasInjectedMembers = true;
+          ValidationReport report = validateMethod(method);
+          if (!report.isClean()) {
+            builder.addSubreport(report);
+          }
+        }
+      }
+
+      if (hasInjectedMembers) {
+        checkInjectIntoPrivateClass(typeElement, builder);
+        checkInjectIntoKotlinObject(typeElement, builder);
+      }
+
+      Optional.ofNullable(typeElement.getSuperType())
+          .filter(supertype -> !supertype.getTypeName().equals(TypeName.OBJECT))
+          .ifPresent(
+              supertype -> {
+                superficialValidation.validateSuperTypeOf(typeElement);
+                ValidationReport report = validateForMembersInjection(supertype.getTypeElement());
+                if (!report.isClean()) {
+                  builder.addSubreport(report);
+                }
+              });
+
+      return builder.build();
+    }
+
+    /** Returns true if the given method element declares a checked exception. */
+    private boolean throwsCheckedExceptions(XConstructorElement constructorElement) {
+      XType runtimeException = processingEnv.findType(TypeNames.RUNTIME_EXCEPTION);
+      XType error = processingEnv.findType(TypeNames.ERROR);
+      superficialValidation.validateThrownTypesOf(constructorElement);
+      return !constructorElement.getThrownTypes().stream()
+          .allMatch(type -> isSubtype(type, runtimeException) || isSubtype(type, error));
+    }
+
+    private void checkInjectIntoPrivateClass(XElement element, ValidationReport.Builder builder) {
+      if (!Accessibility.isElementAccessibleFromOwnPackage(closestEnclosingTypeElement(element))) {
+        builder.addItem(
+            "Dagger does not support injection into private classes",
+            privateMemberDiagnosticKind,
+            element);
       }
     }
 
-    if (hasInjectedMembers) {
-      checkInjectIntoPrivateClass(typeElement, builder);
-      checkInjectIntoKotlinObject(typeElement, builder);
+    private void checkInjectIntoKotlinObject(
+        XTypeElement element, ValidationReport.Builder builder) {
+      if (element.isKotlinObject() || element.isCompanionObject()) {
+        builder.addError("Dagger does not support injection into Kotlin objects", element);
+      }
     }
 
-    Optional.ofNullable(typeElement.getSuperType())
-        .filter(supertype -> !supertype.getTypeName().equals(TypeName.OBJECT))
-        .ifPresent(
-            supertype -> {
-              superficialValidation.validateSuperTypeOf(typeElement);
-              ValidationReport report = validateForMembersInjection(supertype.getTypeElement());
-              if (!report.isClean()) {
-                builder.addSubreport(report);
-              }
-            });
-
-    return builder.build();
-  }
-
-  /** Returns true if the given method element declares a checked exception. */
-  private boolean throwsCheckedExceptions(XConstructorElement constructorElement) {
-    XType runtimeException = processingEnv.findType(TypeNames.RUNTIME_EXCEPTION);
-    XType error = processingEnv.findType(TypeNames.ERROR);
-    superficialValidation.validateThrownTypesOf(constructorElement);
-    return !constructorElement.getThrownTypes().stream()
-        .allMatch(type -> isSubtype(type, runtimeException) || isSubtype(type, error));
-  }
-
-  private void checkInjectIntoPrivateClass(XElement element, ValidationReport.Builder builder) {
-    if (!Accessibility.isElementAccessibleFromOwnPackage(closestEnclosingTypeElement(element))) {
-      builder.addItem(
-          "Dagger does not support injection into private classes",
-          privateMemberDiagnosticKind(),
-          element);
+    private boolean processedInPreviousRoundOrCompilationUnit(
+        XConstructorElement injectConstructor) {
+      return processingEnv.findTypeElement(factoryNameForElement(injectConstructor)) != null;
     }
-  }
 
-  private void checkInjectIntoKotlinObject(XTypeElement element, ValidationReport.Builder builder) {
-    if (element.isKotlinObject() || element.isCompanionObject()) {
-      builder.addError("Dagger does not support injection into Kotlin objects", element);
+    private boolean processedInPreviousRoundOrCompilationUnit(XTypeElement membersInjectedType) {
+      return processingEnv.findTypeElement(membersInjectorNameForType(membersInjectedType)) != null;
     }
   }
-
-  private Diagnostic.Kind privateMemberDiagnosticKind() {
-    return privateAndStaticInjectionDiagnosticKind.orElse(
-        compilerOptions.privateMemberValidationKind());
-  }
-
-  private Diagnostic.Kind staticMemberDiagnosticKind() {
-    return privateAndStaticInjectionDiagnosticKind.orElse(
-        compilerOptions.staticMemberValidationKind());
-  }
-
-  private boolean processedInPreviousRoundOrCompilationUnit(XConstructorElement injectConstructor) {
-    return processingEnv.findTypeElement(factoryNameForElement(injectConstructor)) != null;
-  }
-
-  private boolean processedInPreviousRoundOrCompilationUnit(XTypeElement membersInjectedType) {
-    return processingEnv.findTypeElement(membersInjectorNameForType(membersInjectedType)) != null;
-  }
 }
diff --git a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java b/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
index a63d974..8638614 100644
--- a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
@@ -16,7 +16,8 @@
 
 package dagger.internal.codegen.validation;
 
-import static dagger.internal.codegen.base.FrameworkTypes.isFrameworkType;
+import static dagger.internal.codegen.base.FrameworkTypes.isMapValueFrameworkType;
+import static dagger.internal.codegen.base.FrameworkTypes.isSetValueFrameworkType;
 import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
 import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
 import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
@@ -95,7 +96,7 @@
       } else if (isWildcard(mapType.valueType())) {
         report.addError(
             bindingMethods("return type cannot use a wildcard as the Map value type."));
-      } else if (isFrameworkType(mapType.valueType())) {
+      } else if (isMapValueFrameworkType(mapType.valueType())) {
         String frameworkTypeName = getSimpleName(mapType.valueType().getTypeElement());
         report.addError(
             bindingMethods(
@@ -108,7 +109,7 @@
         report.addError(bindingMethods("return type cannot be a raw Set type"));
       } else if (isWildcard(setType.elementType())) {
         report.addError(bindingMethods("return type cannot use a wildcard as the Set value type."));
-      } else if (isFrameworkType(setType.elementType())) {
+      } else if (isSetValueFrameworkType(setType.elementType())) {
         String frameworkTypeName = getSimpleName(setType.elementType().getTypeElement());
         report.addError(
             bindingMethods(
diff --git a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
index 9b4c16c..35b223a 100644
--- a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
@@ -28,8 +28,8 @@
 import androidx.room.compiler.processing.XType;
 import com.google.common.util.concurrent.ListenableFuture;
 import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.binding.Nullability;
 import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.xprocessing.Nullability;
 import dagger.internal.codegen.xprocessing.XTypes;
 import java.util.Optional;
 import java.util.Set;
diff --git a/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java b/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java
index 42e1adf..ef9e24b 100644
--- a/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java
+++ b/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.validation;
 
+import static androidx.room.compiler.processing.XElementKt.isMethod;
 import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
 import static androidx.room.compiler.processing.compat.XConverters.toJavac;
 import static androidx.room.compiler.processing.compat.XConverters.toKS;
@@ -46,7 +47,8 @@
 import com.google.devtools.ksp.symbol.KSAnnotated;
 import com.google.devtools.ksp.symbol.KSAnnotation;
 import com.google.devtools.ksp.symbol.KSClassDeclaration;
-import com.google.devtools.ksp.symbol.KSFunctionDeclaration;
+import com.google.devtools.ksp.symbol.KSDeclaration;
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration;
 import com.google.devtools.ksp.symbol.KSType;
 import dagger.internal.codegen.xprocessing.XAnnotations;
 import dagger.internal.codegen.xprocessing.XElements;
@@ -575,9 +577,12 @@
     }
 
     @Override
-    public KSFunctionDeclaration ksp() {
+    public KSDeclaration ksp() {
       checkIsKsp(backend());
-      return toKS(executableElement());
+      return isMethod(executableElement())
+              && XElements.asMethod(executableElement()).isKotlinPropertyMethod()
+          ? (KSPropertyDeclaration) toKS((XElement) executableElement())
+          : toKS(executableElement());
     }
 
     @Override
diff --git a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java b/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
index 23faf75..08f6153 100644
--- a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
+++ b/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static androidx.room.compiler.processing.XTypeKt.isArray;
 import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
@@ -95,7 +96,7 @@
 
   @Override
   public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement annotationType) {
-    ClassName generatedTypeName = getAnnotationCreatorClassName(annotationType);
+    ClassName generatedTypeName = toJavaPoet(getAnnotationCreatorClassName(annotationType));
     TypeSpec.Builder annotationCreatorBuilder =
         classBuilder(generatedTypeName)
             .addModifiers(PUBLIC, FINAL)
@@ -146,11 +147,15 @@
       XTypeElement annotationElement, Set<XTypeElement> annotationElements) {
     if (annotationElements.add(annotationElement)) {
       for (XMethodElement method : annotationElement.getDeclaredMethods()) {
-        XTypeElement returnType = method.getReturnType().getTypeElement();
+        XType returnType = method.getReturnType();
+        XTypeElement maybeAnnotationType =
+            isArray(returnType)
+                ? asArray(returnType).getComponentType().getTypeElement()
+                : returnType.getTypeElement();
         // Return type may be null if it doesn't return a type or type is not known
-        if (returnType != null && returnType.isAnnotationClass()) {
+        if (maybeAnnotationType != null && maybeAnnotationType.isAnnotationClass()) {
           // Ignore the return value since this method is just an accumulator method.
-          nestedAnnotationElements(returnType, annotationElements);
+          nestedAnnotationElements(maybeAnnotationType, annotationElements);
         }
       }
     }
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
index 93a8ce5..4735447 100644
--- a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
 import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedFactoryParameterSpecs;
 import static dagger.internal.codegen.xprocessing.MethodSpecs.overriding;
@@ -34,11 +33,11 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.AssistedFactoryBinding;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.model.DependencyRequest;
 import java.util.Optional;
 
 /**
@@ -46,14 +45,14 @@
  * dagger.assisted.AssistedFactory} methods.
  */
 final class AssistedFactoryRequestRepresentation extends RequestRepresentation {
-  private final ProvisionBinding binding;
+  private final AssistedFactoryBinding binding;
   private final BindingGraph graph;
   private final SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory;
   private final ComponentImplementation componentImplementation;
 
   @AssistedInject
   AssistedFactoryRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted AssistedFactoryBinding binding,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
       SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory) {
@@ -65,16 +64,14 @@
 
   @Override
   Expression getDependencyExpression(ClassName requestingClass) {
-    // An assisted factory binding should have a single request for an assisted injection type.
-    DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
     // Get corresponding assisted injection binding.
-    Optional<Binding> localBinding = graph.localContributionBinding(assistedInjectionRequest.key());
+    Optional<Binding> localBinding = graph.localContributionBinding(binding.assistedInjectKey());
     checkArgument(
         localBinding.isPresent(),
         "assisted factory should have a dependency on an assisted injection binding");
     Expression assistedInjectionExpression =
         simpleMethodRequestRepresentationFactory
-            .create((ProvisionBinding) localBinding.get())
+            .create((AssistedInjectionBinding) localBinding.get())
             .getDependencyExpression(requestingClass.peerClass(""));
     return Expression.create(
         assistedInjectionExpression.type(),
@@ -116,6 +113,6 @@
 
   @AssistedFactory
   static interface Factory {
-    AssistedFactoryRequestRepresentation create(ProvisionBinding binding);
+    AssistedFactoryRequestRepresentation create(AssistedFactoryBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java b/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java
index f74b50a..df55b93 100644
--- a/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java
+++ b/java/dagger/internal/codegen/writing/ComponentCreatorImplementationFactory.java
@@ -320,7 +320,7 @@
               "$T.checkBuilderRequirement($N, $T.class)",
               Preconditions.class,
               field,
-              TypeNames.rawTypeName(field.type));
+              TypeNames.rawTypeName(field.type.withoutAnnotations()));
           break;
         case ALLOW:
           break;
@@ -498,7 +498,7 @@
 
     @Override
     protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
-      String name = simpleVariableName(requirement.typeElement().getClassName());
+      String name = simpleVariableName(requirement.typeElement().asClassName());
       return methodBuilder(name)
           .addModifiers(PUBLIC)
           .addParameter(requirement.type().getTypeName(), name)
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
index a41b1c7..4583396 100644
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java
@@ -16,6 +16,8 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
+import static androidx.room.compiler.codegen.compat.XConverters.toXPoet;
 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
@@ -42,6 +44,7 @@
 import static javax.lang.model.element.Modifier.STATIC;
 import static javax.tools.Diagnostic.Kind.ERROR;
 
+import androidx.room.compiler.processing.JavaPoetExtKt;
 import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XMessager;
 import androidx.room.compiler.processing.XMethodElement;
@@ -58,7 +61,7 @@
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.MultimapBuilder;
-import com.google.common.collect.Sets;
+import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
@@ -80,6 +83,7 @@
 import dagger.internal.codegen.binding.ComponentRequirement;
 import dagger.internal.codegen.binding.KeyVariableNamer;
 import dagger.internal.codegen.binding.MethodSignature;
+import dagger.internal.codegen.binding.ModuleDescriptor;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.CodeBlocks;
 import dagger.internal.codegen.javapoet.TypeNames;
@@ -91,6 +95,7 @@
 import dagger.internal.codegen.xprocessing.XTypeElements;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -244,8 +249,12 @@
   /**
    * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
    * before they get partitioned.
+   *
+   * <p>This value has been set based on empirical performance analysis. If this number is too
+   * large, some Android runtimes will not ahead-of-time compile the generated code. See
+   * b/316617683.
    */
-  private static final int STATEMENTS_PER_METHOD = 100;
+  private static final int STATEMENTS_PER_METHOD = 25;
 
   private final ShardImplementation componentShard;
   private final Supplier<ImmutableMap<Binding, ShardImplementation>> shardsByBinding;
@@ -291,7 +300,8 @@
     this.processingEnv = processingEnv;
 
     // The first group of keys belong to the component itself. We call this the componentShard.
-    this.componentShard = new ShardImplementation(componentNames.get(graph.componentPath()));
+    this.componentShard =
+        new ShardImplementation(toJavaPoet(componentNames.get(graph.componentPath())));
 
     // Claim the method names for all local and inherited methods on the component type.
     XTypeElements.getAllNonPrivateInstanceMethods(graph.componentTypeElement()).stream()
@@ -376,8 +386,8 @@
                   ClassName fieldType = componentImpl.name();
                   String fieldName =
                       componentImpl.isNested()
-                          ? simpleVariableName(componentImpl.name())
-                          : simpleVariableName(component);
+                          ? simpleVariableName(toXPoet(componentImpl.name()))
+                          : simpleVariableName(toXPoet(component));
                   FieldSpec.Builder field =
                       FieldSpec.builder(
                           fieldType,
@@ -426,7 +436,7 @@
    * generated class unless this is a top-level component, in which case it will be nested.
    */
   public ClassName getCreatorName() {
-    return componentNames.getCreatorName(graph.componentPath());
+    return toJavaPoet(componentNames.getCreatorName(graph.componentPath()));
   }
 
   /** Generates the component and returns the resulting {@link TypeSpec}. */
@@ -437,7 +447,7 @@
   /**
    * The implementation of a shard.
    *
-   * <p>The purpose of a shard is to allow a component implemenation to be split into multiple
+   * <p>The purpose of a shard is to allow a component implementation to be split into multiple
    * classes, where each class owns the creation logic for a set of keys. Sharding is useful for
    * large component implementations, where a single component implementation class can reach size
    * limitations, such as the constant pool size.
@@ -456,7 +466,6 @@
     private final UniqueNameSet assistedParamNames = new UniqueNameSet();
     private final List<CodeBlock> initializations = new ArrayList<>();
     private final SwitchingProviders switchingProviders;
-    private final LazyClassKeyProviders lazyClassKeyProviders;
     private final Map<Key, CodeBlock> cancellations = new LinkedHashMap<>();
     private final Map<XVariableElement, String> uniqueAssistedName = new LinkedHashMap<>();
     private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
@@ -473,7 +482,6 @@
     private ShardImplementation(ClassName name) {
       this.name = name;
       this.switchingProviders = new SwitchingProviders(this, processingEnv);
-      this.lazyClassKeyProviders = new LazyClassKeyProviders(this);
       if (graph.componentDescriptor().isProduction()) {
         claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
       }
@@ -487,8 +495,26 @@
                       requirement -> requirement,
                       requirement ->
                           ParameterSpec.builder(
-                                  requirement.type().getTypeName(),
+                                  requirement
+                                      .type()
+                                      .getTypeName()
+                                      .annotated(
+                                          requirement
+                                              .getNullability()
+                                              .typeUseNullableAnnotations()
+                                              .stream()
+                                              .map(AnnotationSpec::builder)
+                                              .map(AnnotationSpec.Builder::build)
+                                              .collect(toImmutableList())),
                                   getUniqueFieldName(requirement.variableName() + "Param"))
+                              .addAnnotations(
+                                  requirement
+                                      .getNullability()
+                                      .nonTypeUseNullableAnnotations()
+                                      .stream()
+                                      .map(AnnotationSpec::builder)
+                                      .map(AnnotationSpec.Builder::build)
+                                      .collect(toImmutableList()))
                               .build()));
     }
 
@@ -507,10 +533,6 @@
       return switchingProviders;
     }
 
-    public LazyClassKeyProviders getLazyClassKeyProviders() {
-      return lazyClassKeyProviders;
-    }
-
     /** Returns the {@link ComponentImplementation} that owns this shard. */
     public ComponentImplementation getComponentImplementation() {
       return ComponentImplementation.this;
@@ -569,7 +591,8 @@
      * {@link Key}.
      */
     ClassName getSubcomponentCreatorSimpleName(Key creatorKey) {
-      return componentNames.getSubcomponentCreatorName(graph.componentPath(), creatorKey);
+      return toJavaPoet(
+          componentNames.getSubcomponentCreatorName(graph.componentPath(), creatorKey));
     }
 
     /**
@@ -612,7 +635,8 @@
     }
 
     /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
-    void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
+    @Override
+    public void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
       typeSuppliers.add(typeSpecSupplier);
     }
 
@@ -706,6 +730,15 @@
     public TypeSpec generate() {
       TypeSpec.Builder builder = classBuilder(name);
 
+      // Ksp requires explicitly associating input classes that are generated with the output class,
+      // otherwise, the cached generated classes won't be discoverable in an incremental build.
+      if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP) {
+        graph.componentDescriptor().modules().stream()
+            .filter(ModuleDescriptor::isImplicitlyIncluded)
+            .forEach(
+                module -> JavaPoetExtKt.addOriginatingElement(builder, module.moduleElement()));
+      }
+
       if (isComponentShard()) {
         TypeSpecs.addSupertype(builder, graph.componentTypeElement());
         addCreator();
@@ -871,10 +904,11 @@
       // Each component method may have been declared by several supertypes. We want to implement
       // only one method for each distinct signature.
       XType componentType = graph.componentTypeElement().getType();
-      Set<MethodSignature> signatures = Sets.newHashSet();
-      for (ComponentMethodDescriptor method : graph.componentDescriptor().entryPointMethods()) {
-        if (signatures.add(
-            MethodSignature.forComponentMethod(method, componentType, processingEnv))) {
+      Set<MethodSignature> methodDescriptors = new HashSet<>();
+      for (ComponentMethodDescriptor method : graph.entryPointMethods()) {
+        MethodSignature signature =
+            MethodSignature.forComponentMethod(method, componentType, processingEnv);
+        if (methodDescriptors.add(signature)) {
           addMethod(
               COMPONENT_METHOD,
               componentRequestRepresentationsProvider.get().getComponentMethod(method));
diff --git a/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java
index b5bed2f..f5d2e52 100644
--- a/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ComponentInstanceRequestRepresentation.java
@@ -21,17 +21,17 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.ComponentBinding;
 import dagger.internal.codegen.javapoet.Expression;
 
 /** A binding expression for the instance of the component itself, i.e. {@code this}. */
 final class ComponentInstanceRequestRepresentation extends RequestRepresentation {
   private final ComponentImplementation componentImplementation;
-  private final ContributionBinding binding;
+  private final ComponentBinding binding;
 
   @AssistedInject
   ComponentInstanceRequestRepresentation(
-      @Assisted ContributionBinding binding, ComponentImplementation componentImplementation) {
+      @Assisted ComponentBinding binding, ComponentImplementation componentImplementation) {
     this.componentImplementation = componentImplementation;
     this.binding = binding;
   }
@@ -47,6 +47,6 @@
 
   @AssistedFactory
   static interface Factory {
-    ComponentInstanceRequestRepresentation create(ContributionBinding binding);
+    ComponentInstanceRequestRepresentation create(ComponentBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ComponentNames.java b/java/dagger/internal/codegen/writing/ComponentNames.java
index b5f2f2f..79344c7 100644
--- a/java/dagger/internal/codegen/writing/ComponentNames.java
+++ b/java/dagger/internal/codegen/writing/ComponentNames.java
@@ -22,6 +22,7 @@
 import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
 import static java.lang.String.format;
 
+import androidx.room.compiler.codegen.XClassName;
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableMap;
@@ -50,16 +51,16 @@
  */
 public final class ComponentNames {
   /** Returns the class name for the top-level generated class. */
-  public static ClassName getTopLevelClassName(ComponentDescriptor componentDescriptor) {
+  public static XClassName getTopLevelClassName(ComponentDescriptor componentDescriptor) {
     checkState(!componentDescriptor.isSubcomponent());
-    ClassName componentName = componentDescriptor.typeElement().getClassName();
-    return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
+    XClassName componentName = componentDescriptor.typeElement().asClassName();
+    return XClassName.Companion.get(componentName.getPackageName(), "Dagger" + classFileName(componentName));
   }
 
   private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
 
   private final CompilerOptions compilerOptions;
-  private final ClassName topLevelClassName;
+  private final XClassName topLevelClassName;
   private final ImmutableMap<ComponentPath, String> namesByPath;
   private final ImmutableMap<ComponentPath, String> creatorNamesByPath;
   private final ImmutableMultimap<Key, ComponentPath> pathsByCreatorKey;
@@ -75,7 +76,7 @@
   }
 
   /** Returns the simple component name for the given {@link ComponentDescriptor}. */
-  ClassName get(ComponentPath componentPath) {
+  XClassName get(ComponentPath componentPath) {
     return compilerOptions.generatedClassExtendsComponent() && componentPath.atRoot()
         ? topLevelClassName
         : topLevelClassName.nestedClass(namesByPath.get(componentPath) + "Impl");
@@ -85,7 +86,7 @@
    * Returns the component descriptor for the component with the given subcomponent creator {@link
    * Key}.
    */
-  ClassName getSubcomponentCreatorName(ComponentPath componentPath, Key creatorKey) {
+  XClassName getSubcomponentCreatorName(ComponentPath componentPath, Key creatorKey) {
     checkArgument(pathsByCreatorKey.containsKey(creatorKey));
     // First, find the subcomponent path corresponding to the subcomponent creator key.
     // The key may correspond to multiple paths, so we need to find the one under this component.
@@ -100,7 +101,7 @@
    * Returns the simple name for the subcomponent creator implementation for the given {@link
    * ComponentDescriptor}.
    */
-  ClassName getCreatorName(ComponentPath componentPath) {
+  XClassName getCreatorName(ComponentPath componentPath) {
     checkArgument(creatorNamesByPath.containsKey(componentPath));
     return topLevelClassName.nestedClass(creatorNamesByPath.get(componentPath));
   }
diff --git a/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java b/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java
index 41c3c46..367fd45 100644
--- a/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ComponentProvisionRequestRepresentation.java
@@ -25,21 +25,21 @@
 import dagger.assisted.AssistedInject;
 import dagger.internal.Preconditions;
 import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ComponentDependencyProvisionBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.Expression;
 
 /** A binding expression for component provision methods. */
 final class ComponentProvisionRequestRepresentation extends RequestRepresentation {
-  private final ProvisionBinding binding;
+  private final ComponentDependencyProvisionBinding binding;
   private final BindingGraph bindingGraph;
   private final ComponentRequirementExpressions componentRequirementExpressions;
   private final CompilerOptions compilerOptions;
 
   @AssistedInject
   ComponentProvisionRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ComponentDependencyProvisionBinding binding,
       BindingGraph bindingGraph,
       ComponentImplementation componentImplementation,
       ComponentRequirementExpressions componentRequirementExpressions,
@@ -72,7 +72,9 @@
   }
 
   static CodeBlock maybeCheckForNull(
-      ProvisionBinding binding, CompilerOptions compilerOptions, CodeBlock invocation) {
+      ComponentDependencyProvisionBinding binding,
+      CompilerOptions compilerOptions,
+      CodeBlock invocation) {
     return binding.shouldCheckForNull(compilerOptions)
         ? CodeBlock.of("$T.checkNotNullFromComponent($L)", Preconditions.class, invocation)
         : invocation;
@@ -80,6 +82,6 @@
 
   @AssistedFactory
   static interface Factory {
-    ComponentProvisionRequestRepresentation create(ProvisionBinding binding);
+    ComponentProvisionRequestRepresentation create(ComponentDependencyProvisionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
index dd34316..0f2a40f 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
@@ -19,17 +19,14 @@
 import static androidx.room.compiler.processing.XTypeKt.isVoid;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
 import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
 import static dagger.internal.codegen.xprocessing.MethodSpecs.overriding;
-import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 import static dagger.internal.codegen.xprocessing.XProcessingEnvs.isPreJava8SourceVersion;
 
-import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XType;
 import com.google.common.collect.ImmutableList;
@@ -47,8 +44,6 @@
 import dagger.internal.codegen.binding.FrameworkType;
 import dagger.internal.codegen.binding.FrameworkTypeMapper;
 import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.RequestKind;
@@ -187,47 +182,26 @@
 
   /** Returns the implementation of a component method. */
   public MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
-    checkArgument(componentMethod.dependencyRequest().isPresent());
-    BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
     return overriding(componentMethod.methodElement(), graph.componentTypeElement().getType())
-        .addCode(
-            request.isRequestKind(RequestKind.MEMBERS_INJECTION)
-                ? getMembersInjectionComponentMethodImplementation(request, componentMethod)
-                : getContributionComponentMethodImplementation(request, componentMethod))
+        .addCode(getComponentMethodCodeBlock(componentMethod))
         .build();
   }
 
-  private CodeBlock getMembersInjectionComponentMethodImplementation(
-      BindingRequest request, ComponentMethodDescriptor componentMethod) {
-    checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
-    XMethodElement methodElement = componentMethod.methodElement();
-    RequestRepresentation requestRepresentation = getRequestRepresentation(request);
-    MembersInjectionBinding binding =
-        ((MembersInjectionRequestRepresentation) requestRepresentation).binding();
-    if (binding.injectionSites().isEmpty()) {
-      // If there are no injection sites either do nothing (if the return type is void) or return
-      // the input instance as-is.
-      return isVoid(methodElement.getReturnType())
-          ? CodeBlock.of("")
-          : CodeBlock.of(
-              "return $L;", getSimpleName(getOnlyElement(methodElement.getParameters())));
+  private CodeBlock getComponentMethodCodeBlock(ComponentMethodDescriptor componentMethod) {
+    Expression expression = getComponentMethodExpression(componentMethod);
+    if (isVoid(componentMethod.methodElement().getReturnType())) {
+      return expression.codeBlock().isEmpty()
+          ? expression.codeBlock()
+          : CodeBlock.of("$L;", expression.codeBlock());
     }
-    Expression expression = getComponentMethodExpression(requestRepresentation, componentMethod);
-    return isVoid(methodElement.getReturnType())
-        ? CodeBlock.of("$L;", expression.codeBlock())
-        : CodeBlock.of("return $L;", expression.codeBlock());
-  }
-
-  private CodeBlock getContributionComponentMethodImplementation(
-      BindingRequest request, ComponentMethodDescriptor componentMethod) {
-    checkArgument(!request.isRequestKind(RequestKind.MEMBERS_INJECTION));
-    Expression expression =
-        getComponentMethodExpression(getRequestRepresentation(request), componentMethod);
     return CodeBlock.of("return $L;", expression.codeBlock());
   }
 
-  private Expression getComponentMethodExpression(
-      RequestRepresentation requestRepresentation, ComponentMethodDescriptor componentMethod) {
+  private Expression getComponentMethodExpression(ComponentMethodDescriptor componentMethod) {
+    checkArgument(componentMethod.dependencyRequest().isPresent());
+    BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
+    RequestRepresentation requestRepresentation = getRequestRepresentation(request);
+
     Expression expression =
         requestRepresentation.getDependencyExpressionForComponentMethod(
             componentMethod, componentImplementation);
@@ -279,9 +253,9 @@
         return membersInjectionBindingRepresentationFactory.create(
             (MembersInjectionBinding) binding);
       case PROVISION:
-        return provisionBindingRepresentationFactory.create((ProvisionBinding) binding);
+        return provisionBindingRepresentationFactory.create((ContributionBinding) binding);
       case PRODUCTION:
-        return productionBindingRepresentationFactory.create((ProductionBinding) binding);
+        return productionBindingRepresentationFactory.create((ContributionBinding) binding);
     }
     throw new AssertionError();
   }
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
index ea82f32..ea03683 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
@@ -19,12 +19,14 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Suppliers.memoize;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.COMPONENT_REQUIREMENT_FIELD;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
 import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.base.Supplier;
+import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
@@ -129,7 +131,22 @@
     private MemberSelect createField() {
       String fieldName = componentShard.getUniqueFieldName(componentRequirement.variableName());
       TypeName fieldType = componentRequirement.type().getTypeName();
-      FieldSpec field = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL).build();
+      FieldSpec field =
+          FieldSpec.builder(
+                  fieldType.annotated(
+                      componentRequirement.getNullability().typeUseNullableAnnotations().stream()
+                          .map(AnnotationSpec::builder)
+                          .map(AnnotationSpec.Builder::build)
+                          .collect(toImmutableList())),
+                  fieldName,
+                  PRIVATE,
+                  FINAL)
+              .addAnnotations(
+                  componentRequirement.getNullability().nonTypeUseNullableAnnotations().stream()
+                      .map(AnnotationSpec::builder)
+                      .map(AnnotationSpec.Builder::build)
+                      .collect(toImmutableList()))
+              .build();
       componentShard.addField(COMPONENT_REQUIREMENT_FIELD, field);
       componentShard.addComponentRequirementInitialization(fieldInitialization(field));
       return MemberSelect.localField(componentShard, fieldName);
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java b/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java
index f9e8f14..6867ded 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementRequestRepresentation.java
@@ -22,6 +22,8 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.BoundInstanceBinding;
+import dagger.internal.codegen.binding.ComponentDependencyBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
 import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.javapoet.Expression;
@@ -52,8 +54,16 @@
   }
 
   @AssistedFactory
-  static interface Factory {
-    ComponentRequirementRequestRepresentation create(
+  abstract static class Factory {
+    abstract ComponentRequirementRequestRepresentation create(
         ContributionBinding binding, ComponentRequirement componentRequirement);
+
+    final ComponentRequirementRequestRepresentation create(BoundInstanceBinding binding) {
+      return create(binding, ComponentRequirement.forBoundInstance(binding));
+    }
+
+    final ComponentRequirementRequestRepresentation create(ComponentDependencyBinding binding) {
+      return create(binding, ComponentRequirement.forDependency(binding));
+    }
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ComponentWrapperImplementation.java b/java/dagger/internal/codegen/writing/ComponentWrapperImplementation.java
index 96a042c..3f8894d 100644
--- a/java/dagger/internal/codegen/writing/ComponentWrapperImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentWrapperImplementation.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.TypeSpec.classBuilder;
 import static dagger.internal.codegen.writing.ComponentNames.getTopLevelClassName;
@@ -23,6 +24,7 @@
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.MultimapBuilder;
 import com.squareup.javapoet.ClassName;
@@ -34,6 +36,8 @@
 import dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind;
 import dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind;
 import dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind;
+import java.util.ArrayList;
+import java.util.List;
 import javax.inject.Inject;
 
 /** Represents the implementation of the generated holder for the components. */
@@ -48,11 +52,12 @@
       MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
   private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
       MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
+  private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
 
   @Inject
   ComponentWrapperImplementation(@TopLevel BindingGraph graph) {
     this.graph = graph;
-    this.name = ComponentNames.getTopLevelClassName(graph.componentDescriptor());
+    this.name = toJavaPoet(ComponentNames.getTopLevelClassName(graph.componentDescriptor()));
   }
 
   @Override
@@ -81,9 +86,15 @@
   }
 
   @Override
+  public void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
+    typeSuppliers.add(typeSpecSupplier);
+  }
+
+  @Override
   public TypeSpec generate() {
     TypeSpec.Builder builder =
-        classBuilder(getTopLevelClassName(graph.componentDescriptor())).addModifiers(FINAL);
+        classBuilder(toJavaPoet(getTopLevelClassName(graph.componentDescriptor())))
+            .addModifiers(FINAL);
 
     if (graph.componentTypeElement().isPublic()) {
       builder.addModifiers(PUBLIC);
@@ -92,6 +103,7 @@
     fieldSpecsMap.asMap().values().forEach(builder::addFields);
     methodSpecsMap.asMap().values().forEach(builder::addMethods);
     typeSpecsMap.asMap().values().forEach(builder::addTypes);
+    typeSuppliers.stream().map(Supplier::get).forEach(builder::addType);
 
     return builder.addMethod(constructorBuilder().addModifiers(PRIVATE).build()).build();
   }
diff --git a/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
index 82c01cf..29b510f 100644
--- a/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
@@ -16,13 +16,11 @@
 
 package dagger.internal.codegen.writing;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.base.RequestKinds.requestType;
 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.model.BindingKind.DELEGATE;
 
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XType;
@@ -34,7 +32,7 @@
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.BindsTypeChecker;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.RequestKind;
@@ -42,7 +40,7 @@
 
 /** A {@link dagger.internal.codegen.writing.RequestRepresentation} for {@code @Binds} methods. */
 final class DelegateRequestRepresentation extends RequestRepresentation {
-  private final ContributionBinding binding;
+  private final DelegateBinding binding;
   private final RequestKind requestKind;
   private final ComponentRequestRepresentations componentRequestRepresentations;
   private final XProcessingEnv processingEnv;
@@ -50,7 +48,7 @@
 
   @AssistedInject
   DelegateRequestRepresentation(
-      @Assisted ContributionBinding binding,
+      @Assisted DelegateBinding binding,
       @Assisted RequestKind requestKind,
       ComponentRequestRepresentations componentRequestRepresentations,
       BindsTypeChecker bindsTypeChecker,
@@ -67,8 +65,7 @@
    * binding it depends on.
    */
   static boolean isBindsScopeStrongerThanDependencyScope(
-      ContributionBinding bindsBinding, BindingGraph graph) {
-    checkArgument(bindsBinding.kind().equals(DELEGATE));
+      DelegateBinding bindsBinding, BindingGraph graph) {
     Binding dependencyBinding =
         graph.contributionBinding(getOnlyElement(bindsBinding.dependencies()).key());
     ScopeKind bindsScope = ScopeKind.get(bindsBinding);
@@ -102,7 +99,7 @@
   }
 
   static boolean instanceRequiresCast(
-      ContributionBinding binding,
+      DelegateBinding binding,
       Expression delegateExpression,
       ClassName requestingClass,
       BindsTypeChecker bindsTypeChecker) {
@@ -130,7 +127,7 @@
     // Casted raw type provider expression has to be wrapped parentheses, otherwise there
     // will be an error when DerivedFromFrameworkInstanceRequestRepresentation appends a `get()` to
     // it.
-    // TODO(wanyingd): change the logic to only add parenthesis when necessary.
+    // TODO(bcorso): change the logic to only add parenthesis when necessary.
     return Expression.create(
         castedExpression.type(), CodeBlock.of("($L)", castedExpression.codeBlock()));
   }
@@ -155,6 +152,6 @@
 
   @AssistedFactory
   static interface Factory {
-    DelegateRequestRepresentation create(ContributionBinding binding, RequestKind requestKind);
+    DelegateRequestRepresentation create(DelegateBinding binding, RequestKind requestKind);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
index 1fbb2cb..7554b7e 100644
--- a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
@@ -24,7 +25,7 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.CodeBlocks;
 import dagger.internal.codegen.model.DependencyRequest;
@@ -34,13 +35,13 @@
 final class DelegatingFrameworkInstanceCreationExpression
     implements FrameworkInstanceCreationExpression {
 
-  private final ContributionBinding binding;
+  private final DelegateBinding binding;
   private final ComponentImplementation componentImplementation;
   private final ComponentRequestRepresentations componentRequestRepresentations;
 
   @AssistedInject
   DelegatingFrameworkInstanceCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted DelegateBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations,
       CompilerOptions compilerOptions) {
@@ -58,11 +59,11 @@
                 bindingRequest(dependency.key(), binding.frameworkType()),
                 componentImplementation.shardImplementation(binding).name())
             .codeBlock(),
-        binding.frameworkType().frameworkClassName());
+        toJavaPoet(binding.frameworkType().frameworkClassName()));
   }
 
   @AssistedFactory
   static interface Factory {
-    DelegatingFrameworkInstanceCreationExpression create(ContributionBinding binding);
+    DelegatingFrameworkInstanceCreationExpression create(DelegateBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
index d83e19d..64c221d 100644
--- a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
@@ -33,8 +33,8 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ComponentDependencyProductionBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 
 /**
@@ -45,14 +45,14 @@
 // TODO(dpb): Resolve with DependencyMethodProviderCreationExpression.
 final class DependencyMethodProducerCreationExpression
     implements FrameworkInstanceCreationExpression {
-  private final ContributionBinding binding;
+  private final ComponentDependencyProductionBinding binding;
   private final ComponentImplementation componentImplementation;
   private final ComponentRequirementExpressions componentRequirementExpressions;
   private final BindingGraph graph;
 
   @AssistedInject
   DependencyMethodProducerCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted ComponentDependencyProductionBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequirementExpressions componentRequirementExpressions,
       BindingGraph graph) {
@@ -104,6 +104,6 @@
 
   @AssistedFactory
   static interface Factory {
-    DependencyMethodProducerCreationExpression create(ContributionBinding binding);
+    DependencyMethodProducerCreationExpression create(ComponentDependencyProductionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
index c54b03c..3a8ff50 100644
--- a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
@@ -24,6 +24,7 @@
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.javapoet.TypeNames.daggerProviderOf;
 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
 import static dagger.internal.codegen.xprocessing.XElements.asMethod;
@@ -34,6 +35,7 @@
 import static javax.lang.model.element.Modifier.STATIC;
 
 import androidx.room.compiler.processing.XMethodElement;
+import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.MethodSpec;
@@ -42,8 +44,8 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.ComponentDependencyProvisionBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
@@ -60,12 +62,12 @@
   private final ComponentRequirementExpressions componentRequirementExpressions;
   private final CompilerOptions compilerOptions;
   private final BindingGraph graph;
-  private final ProvisionBinding binding;
+  private final ComponentDependencyProvisionBinding binding;
   private final XMethodElement provisionMethod;
 
   @AssistedInject
   DependencyMethodProviderCreationExpression(
-      @Assisted ProvisionBinding binding,
+      @Assisted ComponentDependencyProvisionBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequirementExpressions componentRequirementExpressions,
       CompilerOptions compilerOptions,
@@ -100,12 +102,16 @@
         methodBuilder("get")
             .addAnnotation(Override.class)
             .addModifiers(PUBLIC)
-            .returns(keyType)
+            .returns(
+                keyType.annotated(
+                    binding.nullability().typeUseNullableAnnotations().stream()
+                        .map(annotation -> AnnotationSpec.builder(annotation).build())
+                        .collect(toImmutableList())))
             .addStatement("return $L", invocation);
 
     binding
         .nullability()
-        .nullableAnnotations()
+        .nonTypeUseNullableAnnotations()
         .forEach(getMethod::addAnnotation);
 
     // We need to use the componentShard here since the generated type is static and shards are
@@ -144,6 +150,6 @@
 
   @AssistedFactory
   static interface Factory {
-    DependencyMethodProviderCreationExpression create(ProvisionBinding binding);
+    DependencyMethodProviderCreationExpression create(ComponentDependencyProvisionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
index f054e6a..3c437a5 100644
--- a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
@@ -28,6 +28,7 @@
 import dagger.internal.codegen.binding.BindsTypeChecker;
 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
 import dagger.internal.codegen.binding.FrameworkType;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.javapoet.TypeNames;
@@ -119,7 +120,8 @@
   private boolean requiresTypeCast(Expression expression, ClassName requestingClass) {
     return binding.kind().equals(BindingKind.DELEGATE)
         && requestKind.equals(RequestKind.INSTANCE)
-        && instanceRequiresCast(binding, expression, requestingClass, bindsTypeChecker);
+        && instanceRequiresCast(
+            (DelegateBinding) binding, expression, requestingClass, bindsTypeChecker);
   }
 
   @AssistedFactory
diff --git a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
index 1eb4249..058ea5f 100644
--- a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
@@ -25,7 +25,7 @@
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.BindingRequest;
 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import java.util.HashMap;
@@ -34,7 +34,7 @@
 
 /** Returns request representation based on a direct instance expression. */
 final class DirectInstanceBindingRepresentation {
-  private final ProvisionBinding binding;
+  private final ContributionBinding binding;
   private final BindingGraph graph;
   private final ComponentImplementation componentImplementation;
   private final ComponentMethodRequestRepresentation.Factory
@@ -49,7 +49,7 @@
 
   @AssistedInject
   DirectInstanceBindingRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
       ComponentMethodRequestRepresentation.Factory componentMethodRequestRepresentationFactory,
@@ -105,7 +105,7 @@
 
     BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
     Optional<ComponentMethodDescriptor> matchingComponentMethod =
-        graph.componentDescriptor().firstMatchingComponentMethod(request);
+        graph.findFirstMatchingComponentMethod(request);
 
     ShardImplementation shardImplementation = componentImplementation.shardImplementation(binding);
 
@@ -133,7 +133,7 @@
     }
   }
 
-  private static boolean requiresMethodEncapsulation(ProvisionBinding binding) {
+  private static boolean requiresMethodEncapsulation(ContributionBinding binding) {
     switch (binding.kind()) {
       case COMPONENT:
       case COMPONENT_PROVISION:
@@ -165,6 +165,6 @@
 
   @AssistedFactory
   static interface Factory {
-    DirectInstanceBindingRepresentation create(ProvisionBinding binding);
+    DirectInstanceBindingRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/FactoryGenerator.java b/java/dagger/internal/codegen/writing/FactoryGenerator.java
index 32195ba..a6a4a71 100644
--- a/java/dagger/internal/codegen/writing/FactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/FactoryGenerator.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
@@ -24,28 +25,43 @@
 import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
 import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.binding.SourceFiles.generatedProxyMethodName;
 import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
 import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
 import static dagger.internal.codegen.javapoet.TypeNames.factoryOf;
 import static dagger.internal.codegen.model.BindingKind.INJECTION;
 import static dagger.internal.codegen.model.BindingKind.PROVISION;
 import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.writing.InjectionMethods.copyParameter;
+import static dagger.internal.codegen.writing.InjectionMethods.copyParameters;
+import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static javax.lang.model.element.Modifier.STATIC;
 
+import androidx.room.compiler.processing.XConstructorElement;
 import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
 import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
@@ -53,12 +69,16 @@
 import com.squareup.javapoet.FieldSpec;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
-import dagger.internal.Factory;
+import dagger.internal.Preconditions;
 import dagger.internal.codegen.base.SourceFileGenerator;
 import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.InjectionBinding;
+import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
 import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.binding.SourceFiles;
 import dagger.internal.codegen.compileroption.CompilerOptions;
@@ -70,16 +90,17 @@
 import dagger.internal.codegen.model.Scope;
 import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
 import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 import javax.inject.Inject;
 
-/**
- * Generates {@link Factory} implementations from {@link ProvisionBinding} instances for {@link
- * Inject} constructors.
- */
-public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding> {
+/** Generates factory implementation for injection, assisted injection, and provision bindings. */
+public final class FactoryGenerator extends SourceFileGenerator<ContributionBinding> {
+  private static final ImmutableSet<BindingKind> VALID_BINDING_KINDS =
+      ImmutableSet.of(BindingKind.INJECTION, BindingKind.ASSISTED_INJECTION, BindingKind.PROVISION);
+
   private final CompilerOptions compilerOptions;
   private final SourceFiles sourceFiles;
 
@@ -95,145 +116,174 @@
   }
 
   @Override
-  public XElement originatingElement(ProvisionBinding binding) {
+  public XElement originatingElement(ContributionBinding binding) {
     // we only create factories for bindings that have a binding element
     return binding.bindingElement().get();
   }
 
   @Override
-  public ImmutableList<TypeSpec.Builder> topLevelTypes(ProvisionBinding binding) {
+  public ImmutableList<TypeSpec.Builder> topLevelTypes(ContributionBinding binding) {
     // We don't want to write out resolved bindings -- we want to write out the generic version.
     checkArgument(!binding.unresolved().isPresent());
     checkArgument(binding.bindingElement().isPresent());
-
-    if (binding.kind() == BindingKind.DELEGATE) {
-      return ImmutableList.of();
-    }
+    checkArgument(VALID_BINDING_KINDS.contains(binding.kind()));
 
     return ImmutableList.of(factoryBuilder(binding));
   }
 
-  private TypeSpec.Builder factoryBuilder(ProvisionBinding binding) {
+  private TypeSpec.Builder factoryBuilder(ContributionBinding binding) {
     TypeSpec.Builder factoryBuilder =
-        classBuilder(generatedClassNameForBinding(binding))
+        classBuilder(toJavaPoet(generatedClassNameForBinding(binding)))
             .addModifiers(PUBLIC, FINAL)
-            .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
-
-    if (binding.kind() == BindingKind.INJECTION
-        || binding.kind() == BindingKind.ASSISTED_INJECTION
-        || binding.kind() == BindingKind.PROVISION) {
-      factoryBuilder.addAnnotation(scopeMetadataAnnotation(binding));
-      factoryBuilder.addAnnotation(qualifierMetadataAnnotation(binding));
-    }
+            .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+            .addAnnotation(scopeMetadataAnnotation(binding))
+            .addAnnotation(qualifierMetadataAnnotation(binding));
 
     factoryTypeName(binding).ifPresent(factoryBuilder::addSuperinterface);
-    addConstructorAndFields(binding, factoryBuilder);
-    factoryBuilder.addMethod(getMethod(binding));
-    addCreateMethod(binding, factoryBuilder);
-
-    factoryBuilder.addMethod(ProvisionMethod.create(binding, compilerOptions));
+    FactoryFields factoryFields = FactoryFields.create(binding);
+    // If the factory has no input fields we can use a static instance holder to create a
+    // singleton instance of the factory. Otherwise, we create a new instance via the constructor.
+    if (factoryFields.isEmpty()) {
+      factoryBuilder.addType(staticInstanceHolderType(binding));
+    } else {
+      factoryBuilder
+          .addFields(factoryFields.getAll())
+          .addMethod(constructorMethod(factoryFields));
+    }
     gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
 
-    return factoryBuilder;
+    return factoryBuilder
+        .addMethod(getMethod(binding, factoryFields))
+        .addMethods(staticCreateMethod(binding, factoryFields))
+        .addMethod(staticProxyMethod(binding));
   }
 
-  private void addConstructorAndFields(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
-    if (FactoryCreationStrategy.of(binding) == FactoryCreationStrategy.SINGLETON_INSTANCE) {
-      return;
+  // private static final class InstanceHolder {
+  //   static final FooModule_ProvidesFooFactory INSTANCE =
+  //       new FooModule_ProvidesFooFactory();
+  // }
+  private TypeSpec staticInstanceHolderType(ContributionBinding binding) {
+    ClassName generatedClassName = toJavaPoet(generatedClassNameForBinding(binding));
+    FieldSpec.Builder instanceHolderFieldBuilder =
+        FieldSpec.builder(generatedClassName, "INSTANCE", STATIC, FINAL)
+            .initializer("new $T()", generatedClassName);
+    if (!bindingTypeElementTypeVariableNames(binding).isEmpty()) {
+      // If the factory has type parameters, ignore them in the field declaration & initializer
+      instanceHolderFieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
     }
+    return TypeSpec.classBuilder(instanceHolderClassName(binding))
+        .addModifiers(PRIVATE, STATIC, FINAL)
+        .addField(instanceHolderFieldBuilder.build())
+        .build();
+  }
+
+  private static ClassName instanceHolderClassName(ContributionBinding binding) {
+    return toJavaPoet(generatedClassNameForBinding(binding).nestedClass("InstanceHolder"));
+  }
+
+  // public FooModule_ProvidesFooFactory(
+  //     FooModule module,
+  //     Provider<Bar> barProvider,
+  //     Provider<Baz> bazProvider) {
+  //   this.module = module;
+  //   this.barProvider = barProvider;
+  //   this.bazProvider = bazProvider;
+  // }
+  private MethodSpec constructorMethod(FactoryFields factoryFields) {
     // TODO(bcorso): Make the constructor private?
     MethodSpec.Builder constructor = constructorBuilder().addModifiers(PUBLIC);
-    constructorParams(binding).forEach(
-        param -> {
-          constructor.addParameter(param).addStatement("this.$1N = $1N", param);
-          factoryBuilder.addField(
-              FieldSpec.builder(param.type, param.name, PRIVATE, FINAL).build());
-        });
-    factoryBuilder.addMethod(constructor.build());
+    factoryFields.getAll().forEach(
+        field ->
+            constructor
+                .addParameter(field.type, field.name)
+                .addStatement("this.$1N = $1N", field));
+    return constructor.build();
   }
 
-  private ImmutableList<ParameterSpec> constructorParams(ProvisionBinding binding) {
-    ImmutableList.Builder<ParameterSpec> params = ImmutableList.builder();
-    moduleParameter(binding).ifPresent(params::add);
-    frameworkFields(binding).values().forEach(field -> params.add(toParameter(field)));
-    return params.build();
-  }
-
-  private Optional<ParameterSpec> moduleParameter(ProvisionBinding binding) {
-    if (binding.requiresModuleInstance()) {
-      // TODO(bcorso, dpb): Should this use contributingModule()?
-      TypeName type = binding.bindingTypeElement().get().getType().getTypeName();
-      return Optional.of(ParameterSpec.builder(type, "module").build());
-    }
-    return Optional.empty();
-  }
-
-  private ImmutableMap<DependencyRequest, FieldSpec> frameworkFields(ProvisionBinding binding) {
-    UniqueNameSet uniqueFieldNames = new UniqueNameSet();
-    // TODO(bcorso, dpb): Add a test for the case when a Factory parameter is named "module".
-    moduleParameter(binding).ifPresent(module -> uniqueFieldNames.claim(module.name));
-    // We avoid Maps.transformValues here because it would implicitly depend on the order in which
-    // the transform function is evaluated on each entry in the map.
-    ImmutableMap.Builder<DependencyRequest, FieldSpec> builder = ImmutableMap.builder();
-    generateBindingFieldsForDependencies(binding).forEach(
-        (dependency, field) ->
-            builder.put(dependency,
-                FieldSpec.builder(
-                        field.type(), uniqueFieldNames.getUniqueName(field.name()), PRIVATE, FINAL)
-                    .build()));
-    return builder.build();
-  }
-
-  private void addCreateMethod(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
-    // If constructing a factory for @Inject or @Provides bindings, we use a static create method
-    // so that generated components can avoid having to refer to the generic types
-    // of the factory.  (Otherwise they may have visibility problems referring to the types.)
+  // Example 1: no dependencies.
+  // public static FooModule_ProvidesFooFactory create() {
+  //   return InstanceHolder.INSTANCE;
+  // }
+  //
+  // Example 2: with dependencies.
+  // public static FooModule_ProvidesFooFactory create(
+  //     FooModule module,
+  //     Provider<Bar> barProvider,
+  //     Provider<Baz> bazProvider) {
+  //   return new FooModule_ProvidesFooFactory(module, barProvider, bazProvider);
+  // }
+  private ImmutableList<MethodSpec> staticCreateMethod(
+      ContributionBinding binding, FactoryFields factoryFields) {
+    // We use a static create method so that generated components can avoid having to refer to the
+    // generic types of the factory.  (Otherwise they may have visibility problems referring to the
+    // types.)
+    ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
     MethodSpec.Builder createMethodBuilder =
         methodBuilder("create")
             .addModifiers(PUBLIC, STATIC)
             .returns(parameterizedGeneratedTypeNameForBinding(binding))
             .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
 
-    switch (FactoryCreationStrategy.of(binding)) {
-      case SINGLETON_INSTANCE:
-        FieldSpec.Builder instanceFieldBuilder =
-            FieldSpec.builder(
-                    generatedClassNameForBinding(binding), "INSTANCE", PRIVATE, STATIC, FINAL)
-                .initializer("new $T()", generatedClassNameForBinding(binding));
-
-        if (!bindingTypeElementTypeVariableNames(binding).isEmpty()) {
-          // If the factory has type parameters, ignore them in the field declaration & initializer
-          instanceFieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
-          createMethodBuilder.addAnnotation(suppressWarnings(UNCHECKED));
-        }
-
-        ClassName instanceHolderName =
-            generatedClassNameForBinding(binding).nestedClass("InstanceHolder");
-        createMethodBuilder.addStatement("return $T.INSTANCE", instanceHolderName);
-        factoryBuilder.addType(
-            TypeSpec.classBuilder(instanceHolderName)
-                .addModifiers(PRIVATE, STATIC, FINAL)
-                .addField(instanceFieldBuilder.build())
-                .build());
-        break;
-      case CLASS_CONSTRUCTOR:
-        List<ParameterSpec> params = constructorParams(binding);
-        createMethodBuilder.addParameters(params);
-        createMethodBuilder.addStatement(
-            "return new $T($L)",
-            parameterizedGeneratedTypeNameForBinding(binding),
-            makeParametersCodeBlock(Lists.transform(params, input -> CodeBlock.of("$N", input))));
-        break;
-      default:
-        throw new AssertionError();
+    if (factoryFields.isEmpty()) {
+      if (!bindingTypeElementTypeVariableNames(binding).isEmpty()) {
+        createMethodBuilder.addAnnotation(suppressWarnings(UNCHECKED));
+      }
+      createMethodBuilder.addStatement("return $T.INSTANCE", instanceHolderClassName(binding));
+    } else {
+      ImmutableList<ParameterSpec> parameters =
+          factoryFields.getAll().stream()
+              .map(field -> ParameterSpec.builder(field.type, field.name).build())
+              .collect(toImmutableList());
+      createMethodBuilder
+          .addParameters(parameters)
+          .addStatement(
+              "return new $T($L)",
+              parameterizedGeneratedTypeNameForBinding(binding),
+              parameterNames(parameters));
+      // If any of the parameters take a Dagger Provider type, we also need to make a
+      // Javax Provider type for backwards compatibility with components generated at
+      // an older version.
+      // Eventually, we will need to remove this and break backwards compatibility
+      // in order to fully cut the Javax dependency.
+      if (hasDaggerProviderParams(parameters)) {
+        methodsBuilder.add(javaxCreateMethod(binding, parameters));
+      }
     }
-    factoryBuilder.addMethod(createMethodBuilder.build());
+    methodsBuilder.add(createMethodBuilder.build());
+    return methodsBuilder.build();
   }
 
-  private MethodSpec getMethod(ProvisionBinding binding) {
+  private MethodSpec javaxCreateMethod(
+      ContributionBinding binding, ImmutableList<ParameterSpec> parameters) {
+    ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(parameters);
+    return methodBuilder("create")
+        .addModifiers(PUBLIC, STATIC)
+        .returns(parameterizedGeneratedTypeNameForBinding(binding))
+        .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+        .addParameters(remappedParams)
+        .addStatement(
+            "return new $T($L)",
+            parameterizedGeneratedTypeNameForBinding(binding),
+            wrappedParametersCodeBlock(remappedParams))
+        .build();
+  }
+
+  // Example 1: Provision binding.
+  // @Override
+  // public Foo get() {
+  //   return provideFoo(module, barProvider.get(), bazProvider.get());
+  // }
+  //
+  // Example 2: Injection binding with some inject field.
+  // @Override
+  // public Foo get() {
+  //   Foo instance = newInstance(barProvider.get(), bazProvider.get());
+  //   Foo_MembersInjector.injectSomeField(instance, someFieldProvider.get());
+  //   return instance;
+  // }
+  private MethodSpec getMethod(ContributionBinding binding, FactoryFields factoryFields) {
     UniqueNameSet uniqueFieldNames = new UniqueNameSet();
-    ImmutableMap<DependencyRequest, FieldSpec> frameworkFields = frameworkFields(binding);
-    frameworkFields.values().forEach(field -> uniqueFieldNames.claim(field.name));
+    factoryFields.getAll().forEach(field -> uniqueFieldNames.claim(field.name));
     ImmutableMap<XExecutableParameterElement, ParameterSpec> assistedParameters =
         assistedParameters(binding).stream()
             .collect(
@@ -258,31 +308,31 @@
             binding,
             request ->
                 sourceFiles.frameworkTypeUsageStatement(
-                    CodeBlock.of("$N", frameworkFields.get(request)), request.kind()),
+                    CodeBlock.of("$N", factoryFields.get(request)), request.kind()),
             param -> assistedParameters.get(param).name,
-            generatedClassNameForBinding(binding),
-            moduleParameter(binding).map(module -> CodeBlock.of("$N", module)),
+            toJavaPoet(generatedClassNameForBinding(binding)),
+            factoryFields.moduleField.map(module -> CodeBlock.of("$N", module)),
             compilerOptions);
 
     if (binding.kind().equals(PROVISION)) {
       binding
           .nullability()
-          .nullableAnnotations()
+          .nonTypeUseNullableAnnotations()
           .forEach(getMethod::addAnnotation);
-      getMethod.returns(providedTypeName);
-      getMethod.addStatement("return $L", invokeNewInstance);
-    } else if (!binding.injectionSites().isEmpty()) {
+      getMethod.addStatement("return $L", invokeNewInstance).returns(providedTypeName);
+    } else if (!injectionSites(binding).isEmpty()) {
       CodeBlock instance = CodeBlock.of("instance");
       getMethod
           .returns(providedTypeName)
           .addStatement("$T $L = $L", providedTypeName, instance, invokeNewInstance)
           .addCode(
               InjectionSiteMethod.invokeAll(
-                  binding.injectionSites(),
-                  generatedClassNameForBinding(binding),
+                  injectionSites(binding),
+                  toJavaPoet(generatedClassNameForBinding(binding)),
                   instance,
                   binding.key().type().xprocessing(),
-                  sourceFiles.frameworkFieldUsages(binding.dependencies(), frameworkFields)::get))
+                  sourceFiles.frameworkFieldUsages(
+                      binding.dependencies(), factoryFields.frameworkFields)::get))
           .addStatement("return $L", instance);
 
     } else {
@@ -293,7 +343,104 @@
     return getMethod.build();
   }
 
-  private AnnotationSpec scopeMetadataAnnotation(ProvisionBinding binding) {
+  private MethodSpec staticProxyMethod(ContributionBinding binding) {
+    switch (binding.kind()) {
+      case INJECTION:
+      case ASSISTED_INJECTION:
+        return staticProxyMethodForInjection(binding);
+      case PROVISION:
+        return staticProxyMethodForProvision((ProvisionBinding) binding);
+      default:
+        throw new AssertionError("Unexpected binding kind: " + binding);
+    }
+  }
+
+  // Example:
+  //
+  // public static Foo newInstance(Bar bar, Baz baz) {
+  //   return new Foo(bar, baz);
+  // }
+  private static MethodSpec staticProxyMethodForInjection(ContributionBinding binding) {
+    XConstructorElement constructor = asConstructor(binding.bindingElement().get());
+    XTypeElement enclosingType = constructor.getEnclosingElement();
+    MethodSpec.Builder builder =
+        methodBuilder(generatedProxyMethodName(binding))
+            .addModifiers(PUBLIC, STATIC)
+            .varargs(constructor.isVarArgs())
+            .returns(enclosingType.getType().getTypeName())
+            .addTypeVariables(typeVariableNames(enclosingType))
+            .addExceptions(getThrownTypes(constructor));
+    CodeBlock arguments = copyParameters(builder, new UniqueNameSet(), constructor.getParameters());
+    return builder
+        .addStatement("return new $T($L)", enclosingType.getType().getTypeName(), arguments)
+        .build();
+  }
+
+  // Example:
+  //
+  // public static Foo provideFoo(FooModule module, Bar bar, Baz baz) {
+  //   return Preconditions.checkNotNullFromProvides(module.provideFoo(bar, baz));
+  // }
+  private MethodSpec staticProxyMethodForProvision(ProvisionBinding binding) {
+    XMethodElement method = asMethod(binding.bindingElement().get());
+    MethodSpec.Builder builder =
+        methodBuilder(generatedProxyMethodName(binding))
+            .addModifiers(PUBLIC, STATIC)
+            .varargs(method.isVarArgs())
+            .addExceptions(getThrownTypes(method));
+
+    XTypeElement enclosingType = asTypeElement(method.getEnclosingElement());
+    UniqueNameSet parameterNameSet = new UniqueNameSet();
+    CodeBlock module;
+    if (method.isStatic() || enclosingType.isCompanionObject()) {
+      module = CodeBlock.of("$T", enclosingType.getClassName());
+    } else if (enclosingType.isKotlinObject()) {
+      // Call through the singleton instance.
+      // See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
+      module = CodeBlock.of("$T.INSTANCE", enclosingType.getClassName());
+    } else {
+      builder.addTypeVariables(typeVariableNames(enclosingType));
+      module = copyInstance(builder, parameterNameSet, enclosingType.getType());
+    }
+    CodeBlock arguments = copyParameters(builder, parameterNameSet, method.getParameters());
+    CodeBlock invocation = CodeBlock.of("$L.$L($L)", module, method.getJvmName(), arguments);
+
+    Nullability nullability = Nullability.of(method);
+    nullability
+        .nonTypeUseNullableAnnotations()
+        .forEach(builder::addAnnotation);
+    return builder
+        .returns(
+            method.getReturnType().getTypeName()
+                .annotated(
+                    nullability.typeUseNullableAnnotations().stream()
+                        .map(annotation -> AnnotationSpec.builder(annotation).build())
+                        .collect(toImmutableList())))
+        .addStatement("return $L", maybeWrapInCheckForNull(binding, invocation))
+        .build();
+  }
+
+  private CodeBlock maybeWrapInCheckForNull(ProvisionBinding binding, CodeBlock codeBlock) {
+    return binding.shouldCheckForNull(compilerOptions)
+        ? CodeBlock.of("$T.checkNotNullFromProvides($L)", Preconditions.class, codeBlock)
+        : codeBlock;
+  }
+
+  private static CodeBlock copyInstance(
+      MethodSpec.Builder methodBuilder, UniqueNameSet parameterNameSet, XType type) {
+    return copyParameter(
+        methodBuilder,
+        type,
+        parameterNameSet.getUniqueName("instance"),
+        /* useObject= */ false,
+        Nullability.NOT_NULLABLE);
+  }
+
+  private static ImmutableList<TypeName> getThrownTypes(XExecutableElement executable) {
+    return executable.getThrownTypes().stream().map(XType::getTypeName).collect(toImmutableList());
+  }
+
+  private AnnotationSpec scopeMetadataAnnotation(ContributionBinding binding) {
     AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.SCOPE_METADATA);
     binding.scope()
         .map(Scope::scopeAnnotation)
@@ -303,12 +450,13 @@
     return builder.build();
   }
 
-  private AnnotationSpec qualifierMetadataAnnotation(ProvisionBinding binding) {
+  private AnnotationSpec qualifierMetadataAnnotation(ContributionBinding binding) {
     AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.QUALIFIER_METADATA);
-    // Collect all qualifiers on the binding itself or its dependencies
+    // Collect all qualifiers on the binding itself or its dependencies. For injection bindings, we
+    // don't include the injection sites, as that is handled by MembersInjectorFactory.
     Stream.concat(
             Stream.of(binding.key()),
-            binding.provisionDependencies().stream().map(DependencyRequest::key))
+            provisionDependencies(binding).stream().map(DependencyRequest::key))
         .map(Key::qualifier)
         .flatMap(presentValues())
         .map(DaggerAnnotation::className)
@@ -318,44 +466,148 @@
     return builder.build();
   }
 
-  private static TypeName providedTypeName(ProvisionBinding binding) {
-    return binding.contributedType().getTypeName();
+  private ImmutableSet<DependencyRequest> provisionDependencies(ContributionBinding binding) {
+    switch (binding.kind()) {
+      case INJECTION:
+        return ((InjectionBinding) binding).constructorDependencies();
+      case ASSISTED_INJECTION:
+        return ((AssistedInjectionBinding) binding).constructorDependencies();
+      case PROVISION:
+        return ((ProvisionBinding) binding).dependencies();
+      default:
+        throw new AssertionError("Unexpected binding kind: " + binding.kind());
+    }
   }
 
-  private static Optional<TypeName> factoryTypeName(ProvisionBinding binding) {
+  private ImmutableSet<InjectionSite> injectionSites(ContributionBinding binding) {
+    switch (binding.kind()) {
+      case INJECTION:
+        return ((InjectionBinding) binding).injectionSites();
+      case ASSISTED_INJECTION:
+        return ((AssistedInjectionBinding) binding).injectionSites();
+      case PROVISION:
+        return ImmutableSet.of();
+      default:
+        throw new AssertionError("Unexpected binding kind: " + binding.kind());
+    }
+  }
+
+  private static TypeName providedTypeName(ContributionBinding binding) {
+    return binding
+        .contributedType()
+        .getTypeName()
+        .annotated(
+            binding.nullability().typeUseNullableAnnotations().stream()
+                .map(annotation -> AnnotationSpec.builder(annotation).build())
+                .collect(toImmutableList()));
+  }
+
+  private static Optional<TypeName> factoryTypeName(ContributionBinding binding) {
     return binding.kind() == BindingKind.ASSISTED_INJECTION
         ? Optional.empty()
         : Optional.of(factoryOf(providedTypeName(binding)));
   }
 
-  private static ParameterSpec toParameter(FieldSpec field) {
-    return ParameterSpec.builder(field.type, field.name).build();
+  // Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
+  static boolean hasDaggerProviderParams(List<ParameterSpec> params) {
+    return params.stream().anyMatch(param -> isDaggerProviderType(param.type));
   }
 
-  /** The strategy for getting an instance of a factory for a {@link Binding}. */
-  private enum FactoryCreationStrategy {
-    /** The factory class is a single instance. */
-    SINGLETON_INSTANCE,
-    /** The factory must be created by calling the constructor. */
-    CLASS_CONSTRUCTOR;
+  // Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
+  // Returns a code block that represents a parameter list where any javax Provider
+  // types are wrapped in an asDaggerProvider call
+  static CodeBlock wrappedParametersCodeBlock(List<ParameterSpec> params) {
+    return makeParametersCodeBlock(
+        Lists.transform(
+            params,
+            input ->
+            isProviderType(input.type)
+            ? CodeBlock.of(
+                "$T.asDaggerProvider($N)", TypeNames.DAGGER_PROVIDERS, input)
+            : CodeBlock.of("$N", input)));
+  }
 
-    static FactoryCreationStrategy of(Binding binding) {
-      switch (binding.kind()) {
-        case DELEGATE:
-          throw new AssertionError("Delegate bindings don't have a factory.");
-        case PROVISION:
-          return binding.dependencies().isEmpty() && !binding.requiresModuleInstance()
-              ? SINGLETON_INSTANCE
-              : CLASS_CONSTRUCTOR;
-        case INJECTION:
-        case MULTIBOUND_SET:
-        case MULTIBOUND_MAP:
-          return binding.dependencies().isEmpty()
-              ? SINGLETON_INSTANCE
-              : CLASS_CONSTRUCTOR;
-        default:
-          return CLASS_CONSTRUCTOR;
+  // Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
+  static ImmutableList<ParameterSpec> remapParamsToJavaxProvider(List<ParameterSpec> params) {
+    return params.stream()
+        .map(param -> ParameterSpec.builder(
+            remapDaggerProviderToProvider(param.type), param.name).build())
+        .collect(toImmutableList());
+  }
+
+  private static boolean isDaggerProviderType(TypeName type) {
+    return type instanceof ParameterizedTypeName
+        && ((ParameterizedTypeName) type).rawType.equals(TypeNames.DAGGER_PROVIDER);
+  }
+
+  private static boolean isProviderType(TypeName type) {
+    return type instanceof ParameterizedTypeName
+        && ((ParameterizedTypeName) type).rawType.equals(TypeNames.PROVIDER);
+  }
+
+  private static TypeName remapDaggerProviderToProvider(TypeName type) {
+    if (type instanceof ParameterizedTypeName) {
+      ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) type;
+      if (parameterizedTypeName.rawType.equals(TypeNames.DAGGER_PROVIDER)) {
+        return ParameterizedTypeName.get(
+            TypeNames.PROVIDER, parameterizedTypeName.typeArguments.toArray(new TypeName[0]));
       }
     }
+    return type;
+  }
+
+  /** Represents the available fields in the generated factory class. */
+  private static final class FactoryFields {
+    static FactoryFields create(ContributionBinding binding) {
+      UniqueNameSet nameSet = new UniqueNameSet();
+      // TODO(bcorso, dpb): Add a test for the case when a Factory parameter is named "module".
+      Optional<FieldSpec> moduleField =
+          binding.requiresModuleInstance()
+              ? Optional.of(
+                  createField(
+                      binding.bindingTypeElement().get().getType().getTypeName(),
+                      nameSet.getUniqueName("module")))
+              : Optional.empty();
+
+      ImmutableMap.Builder<DependencyRequest, FieldSpec> frameworkFields = ImmutableMap.builder();
+      generateBindingFieldsForDependencies(binding).forEach(
+          (dependency, field) ->
+              frameworkFields.put(
+                  dependency,
+                  createField(toJavaPoet(field.type()), nameSet.getUniqueName(field.name()))));
+
+      return new FactoryFields(moduleField, frameworkFields.buildOrThrow());
+    }
+
+    private static FieldSpec createField(TypeName type, String name) {
+      return FieldSpec.builder(type, name, PRIVATE, FINAL).build();
+    }
+
+    private final Optional<FieldSpec> moduleField;
+    private final ImmutableMap<DependencyRequest, FieldSpec> frameworkFields;
+
+    private FactoryFields(
+        Optional<FieldSpec> moduleField,
+        ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
+      this.moduleField = moduleField;
+      this.frameworkFields = frameworkFields;
+    }
+
+    FieldSpec get(DependencyRequest request) {
+      return frameworkFields.get(request);
+    }
+
+    ImmutableList<FieldSpec> getAll() {
+      return moduleField.isPresent()
+          ? ImmutableList.<FieldSpec>builder()
+              .add(moduleField.get())
+              .addAll(frameworkFields.values())
+              .build()
+          : frameworkFields.values().asList();
+    }
+
+    boolean isEmpty() {
+      return getAll().isEmpty();
+    }
   }
 }
diff --git a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
index 32f0dde..28dbaba 100644
--- a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
@@ -16,18 +16,19 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
 import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
+import androidx.room.compiler.codegen.XClassName;
+import androidx.room.compiler.codegen.XTypeName;
 import androidx.room.compiler.processing.XType;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
 import dagger.internal.DelegateFactory;
 import dagger.internal.codegen.binding.BindingType;
 import dagger.internal.codegen.binding.ContributionBinding;
@@ -36,6 +37,7 @@
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
+import dagger.internal.codegen.xprocessing.XTypeNames;
 import java.util.Optional;
 
 /**
@@ -56,7 +58,7 @@
      * Returns the framework class to use for the field, if different from the one implied by the
      * binding. This implementation returns {@link Optional#empty()}.
      */
-    default Optional<ClassName> alternativeFrameworkClass() {
+    default Optional<XClassName> alternativeFrameworkClass() {
       return Optional.empty();
     }
   }
@@ -142,26 +144,27 @@
         FrameworkField.forBinding(
             binding, frameworkInstanceCreationExpression.alternativeFrameworkClass());
 
-    TypeName fieldType = useRawType
-        ? TypeNames.rawTypeName(contributionBindingField.type())
+    XTypeName fieldType = useRawType
+        ? contributionBindingField.type().getRawTypeName()
         : contributionBindingField.type();
 
     if (binding.kind() == BindingKind.ASSISTED_INJECTION) {
       // An assisted injection factory doesn't extend Provider, so we reference the generated
       // factory type directly (i.e. Foo_Factory<T> instead of Provider<Foo<T>>).
-      TypeName[] typeParameters =
+      XTypeName[] typeParameters =
           binding.key().type().xprocessing().getTypeArguments().stream()
-              .map(XType::getTypeName)
-              .toArray(TypeName[]::new);
+              .map(XType::asTypeName)
+              .toArray(XTypeName[]::new);
       fieldType =
           typeParameters.length == 0
               ? generatedClassNameForBinding(binding)
-              : ParameterizedTypeName.get(generatedClassNameForBinding(binding), typeParameters);
+              : generatedClassNameForBinding(binding).parametrizedBy(typeParameters);
     }
 
     FieldSpec.Builder contributionField =
         FieldSpec.builder(
-            fieldType, shardImplementation.getUniqueFieldName(contributionBindingField.name()));
+            toJavaPoet(fieldType),
+            shardImplementation.getUniqueFieldName(contributionBindingField.name()));
     contributionField.addModifiers(PRIVATE);
     if (useRawType) {
       contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
@@ -181,7 +184,7 @@
     return binding.bindingType().equals(BindingType.PROVISION)
         && frameworkInstanceCreationExpression
             .alternativeFrameworkClass()
-            .map(TypeNames.PROVIDER::equals)
+            .map(XTypeNames.PROVIDER::equals)
             .orElse(true);
   }
 
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
index 037df56..0132a1f 100644
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
@@ -26,15 +26,16 @@
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
 import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.model.RequestKind;
 import java.util.HashMap;
 import java.util.Map;
 
 /** Returns request representation that wraps a framework instance expression */
 final class FrameworkInstanceBindingRepresentation {
-  private final ProvisionBinding binding;
+  private final ContributionBinding binding;
   private final DerivedFromFrameworkInstanceRequestRepresentation.Factory
       derivedFromFrameworkInstanceRequestRepresentationFactory;
   private final ImmediateFutureRequestRepresentation.Factory
@@ -45,7 +46,7 @@
 
   @AssistedInject
   FrameworkInstanceBindingRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
       DelegateRequestRepresentation.Factory delegateRequestRepresentationFactory,
@@ -63,7 +64,8 @@
     this.immediateFutureRequestRepresentationFactory = immediateFutureRequestRepresentationFactory;
     this.providerRequestRepresentation =
         binding.kind().equals(DELEGATE) && !needsCaching(binding, graph)
-            ? delegateRequestRepresentationFactory.create(binding, RequestKind.PROVIDER)
+            ? delegateRequestRepresentationFactory.create(
+                (DelegateBinding) binding, RequestKind.PROVIDER)
             : providerInstanceRequestRepresentationFactory.create(binding);
     this.producerFromProviderRepresentation =
         producerNodeInstanceRequestRepresentationFactory.create(
@@ -107,6 +109,6 @@
 
   @AssistedFactory
   static interface Factory {
-    FrameworkInstanceBindingRepresentation create(ProvisionBinding binding);
+    FrameworkInstanceBindingRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java
index cb64b02..04ac362 100644
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceRequestRepresentation.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
 import static dagger.internal.codegen.xprocessing.XProcessingEnvs.wrapType;
@@ -51,7 +52,10 @@
   Expression getDependencyExpression(ClassName requestingClass) {
     MemberSelect memberSelect = frameworkInstanceSupplier.memberSelect();
     XType expressionType =
-        wrapType(frameworkType().frameworkClassName(), binding.contributedType(), processingEnv);
+        wrapType(
+            toJavaPoet(frameworkType().frameworkClassName()),
+            binding.contributedType(),
+            processingEnv);
     return Expression.create(
         isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName())
                 || isInlinedFactoryCreation(memberSelect)
diff --git a/java/dagger/internal/codegen/writing/GeneratedImplementation.java b/java/dagger/internal/codegen/writing/GeneratedImplementation.java
index 032a3c4..cea01f7 100644
--- a/java/dagger/internal/codegen/writing/GeneratedImplementation.java
+++ b/java/dagger/internal/codegen/writing/GeneratedImplementation.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import com.google.common.base.Supplier;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.FieldSpec;
 import com.squareup.javapoet.MethodSpec;
@@ -41,6 +42,9 @@
   /** Adds the given type to the generated implementation. */
   void addType(TypeSpecKind typeKind, TypeSpec typeSpec);
 
+  /** Adds a {@link Supplier} for a {@link TypeSpec} to the generated implementation. */
+  void addTypeSupplier(Supplier<TypeSpec> typeSupplier);
+
   /** Returns the {@link TypeSpec} for this generated implementation. */
   public TypeSpec generate();
 }
diff --git a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java b/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
index 3eaf92d..2c855cc 100644
--- a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
+++ b/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
@@ -32,7 +32,6 @@
 import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.MapKeys;
 import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.model.DaggerAnnotation;
 import javax.inject.Inject;
 
 /**
@@ -72,7 +71,6 @@
               // Note: the generated field should not be initialized to avoid class loading.
               binding
                   .mapKey()
-                  .map(DaggerAnnotation::xprocessing)
                   .filter(
                       mapKey ->
                           mapKey.getTypeElement().getClassName().equals(TypeNames.LAZY_CLASS_KEY))
diff --git a/java/dagger/internal/codegen/writing/InjectionMethods.java b/java/dagger/internal/codegen/writing/InjectionMethods.java
index 39c03dd..360adf1 100644
--- a/java/dagger/internal/codegen/writing/InjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/InjectionMethods.java
@@ -16,47 +16,28 @@
 
 package dagger.internal.codegen.writing;
 
-import static androidx.room.compiler.processing.XElementKt.isConstructor;
-import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
-import static androidx.room.compiler.processing.XTypeKt.isVoid;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
+import static dagger.internal.codegen.binding.SourceFiles.generatedProxyMethodName;
+import static dagger.internal.codegen.binding.SourceFiles.membersInjectorMethodName;
 import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
 import static dagger.internal.codegen.javapoet.CodeBlocks.toConcatenatedCodeBlock;
 import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
-import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
 import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
 import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
-import static dagger.internal.codegen.xprocessing.XElements.asConstructor;
 import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
-import static dagger.internal.codegen.xprocessing.XElements.asField;
-import static dagger.internal.codegen.xprocessing.XElements.asMethod;
 import static dagger.internal.codegen.xprocessing.XElements.asMethodParameter;
-import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
 import static dagger.internal.codegen.xprocessing.XTypes.erasedTypeName;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
 
-import androidx.room.compiler.processing.XAnnotation;
-import androidx.room.compiler.processing.XConstructorElement;
 import androidx.room.compiler.processing.XExecutableElement;
 import androidx.room.compiler.processing.XExecutableParameterElement;
-import androidx.room.compiler.processing.XFieldElement;
-import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XType;
-import androidx.room.compiler.processing.XTypeElement;
 import androidx.room.compiler.processing.XVariableElement;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -67,17 +48,15 @@
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeName;
-import dagger.internal.Preconditions;
 import dagger.internal.codegen.base.UniqueNameSet;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.InjectionBinding;
 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.Nullability;
 import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.extension.DaggerCollectors;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.model.DaggerAnnotation;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.Nullability;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.Function;
@@ -111,38 +90,13 @@
    * </code></pre>
    */
   static final class ProvisionMethod {
-    // These names are already defined in factories and shouldn't be used for the proxy method name.
-    private static final ImmutableSet<String> BANNED_PROXY_NAMES = ImmutableSet.of("get", "create");
-
-    /**
-     * Returns a method that invokes the binding's {@linkplain ProvisionBinding#bindingElement()
-     * constructor} and injects the instance's members.
-     */
-    static MethodSpec create(ProvisionBinding binding, CompilerOptions compilerOptions) {
-      XExecutableElement executableElement = asExecutable(binding.bindingElement().get());
-      if (isConstructor(executableElement)) {
-        return constructorProxy(asConstructor(executableElement));
-      } else if (isMethod(executableElement)) {
-        XMethodElement method = asMethod(executableElement);
-        String methodName =
-            BANNED_PROXY_NAMES.contains(getSimpleName(method))
-                ? "proxy" + LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(method))
-                : getSimpleName(method);
-        return methodProxy(
-            method,
-            methodName,
-            InstanceCastPolicy.IGNORE,
-            CheckNotNullPolicy.get(binding, compilerOptions));
-      }
-      throw new AssertionError(executableElement);
-    }
 
     /**
      * Invokes the injection method for {@code binding}, with the dependencies transformed with the
      * {@code dependencyUsage} function.
      */
     static CodeBlock invoke(
-        ProvisionBinding binding,
+        ContributionBinding binding,
         Function<DependencyRequest, CodeBlock> dependencyUsage,
         Function<XExecutableParameterElement, String> uniqueAssistedParameterName,
         ClassName requestingClass,
@@ -153,17 +107,17 @@
       invokeArguments(binding, dependencyUsage, uniqueAssistedParameterName)
           .forEach(arguments::add);
 
-      ClassName enclosingClass = generatedClassNameForBinding(binding);
-      MethodSpec methodSpec = create(binding, compilerOptions);
-      return invokeMethod(methodSpec, arguments.build(), enclosingClass, requestingClass);
+      ClassName enclosingClass = toJavaPoet(generatedClassNameForBinding(binding));
+      String methodName = generatedProxyMethodName(binding);
+      return invokeMethod(methodName, arguments.build(), enclosingClass, requestingClass);
     }
 
     static ImmutableList<CodeBlock> invokeArguments(
-        ProvisionBinding binding,
+        ContributionBinding binding,
         Function<DependencyRequest, CodeBlock> dependencyUsage,
         Function<XExecutableParameterElement, String> uniqueAssistedParameterName) {
       ImmutableMap<XExecutableParameterElement, DependencyRequest> dependencyRequestMap =
-          binding.provisionDependencies().stream()
+          provisionDependencies(binding).stream()
               .collect(
                   toImmutableMap(
                       request -> asMethodParameter(request.requestElement().get().xprocessing()),
@@ -185,38 +139,18 @@
       return arguments.build();
     }
 
-    private static MethodSpec constructorProxy(XConstructorElement constructor) {
-      XTypeElement enclosingType = constructor.getEnclosingElement();
-      MethodSpec.Builder builder =
-          methodBuilder("newInstance")
-              .addModifiers(PUBLIC, STATIC)
-              .varargs(constructor.isVarArgs())
-              .returns(enclosingType.getType().getTypeName())
-              .addTypeVariables(typeVariableNames(enclosingType));
-
-      copyThrows(builder, constructor);
-
-      CodeBlock arguments =
-          copyParameters(builder, new UniqueNameSet(), constructor.getParameters());
-      return builder
-          .addStatement("return new $T($L)", enclosingType.getType().getTypeName(), arguments)
-          .build();
-    }
-
-    /**
-     * Returns {@code true} if injecting an instance of {@code binding} from {@code callingPackage}
-     * requires the use of an injection method.
-     */
-    static boolean requiresInjectionMethod(
-        ProvisionBinding binding, CompilerOptions compilerOptions, ClassName requestingClass) {
-      XExecutableElement executableElement = asExecutable(binding.bindingElement().get());
-      return !binding.injectionSites().isEmpty()
-          || binding.shouldCheckForNull(compilerOptions)
-          || !isElementAccessibleFrom(executableElement, requestingClass.packageName())
-          // This check should be removable once we drop support for -source 7
-          || executableElement.getParameters().stream()
-              .map(XExecutableParameterElement::getType)
-              .anyMatch(type -> !isRawTypeAccessible(type, requestingClass.packageName()));
+    private static ImmutableSet<DependencyRequest> provisionDependencies(
+        ContributionBinding binding) {
+      switch (binding.kind()) {
+        case INJECTION:
+          return ((InjectionBinding) binding).constructorDependencies();
+        case ASSISTED_INJECTION:
+          return ((AssistedInjectionBinding) binding).constructorDependencies();
+        case PROVISION:
+          return ((ProvisionBinding) binding).dependencies();
+        default:
+          throw new AssertionError("Unexpected binding kind: " + binding.kind());
+      }
     }
   }
 
@@ -239,35 +173,6 @@
    */
   static final class InjectionSiteMethod {
     /**
-     * When a type has an inaccessible member from a supertype (e.g. an @Inject field in a parent
-     * that's in a different package), a method in the supertype's package must be generated to give
-     * the subclass's members injector a way to inject it. Each potentially inaccessible member
-     * receives its own method, as the subclass may need to inject them in a different order from
-     * the parent class.
-     */
-    static MethodSpec create(InjectionSite injectionSite) {
-      String methodName = methodName(injectionSite);
-      switch (injectionSite.kind()) {
-        case METHOD:
-          return methodProxy(
-              asMethod(injectionSite.element()),
-              methodName,
-              InstanceCastPolicy.CAST_IF_NOT_PUBLIC,
-              CheckNotNullPolicy.IGNORE);
-        case FIELD:
-          Optional<XAnnotation> qualifier =
-              injectionSite.dependencies().stream()
-                  // methods for fields have a single dependency request
-                  .collect(DaggerCollectors.onlyElement())
-                  .key()
-                  .qualifier()
-                  .map(DaggerAnnotation::xprocessing);
-          return fieldProxy(asField(injectionSite.element()), methodName, qualifier);
-      }
-      throw new AssertionError(injectionSite);
-    }
-
-    /**
      * Invokes each of the injection methods for {@code injectionSites}, with the dependencies
      * transformed using the {@code dependencyUsage} function.
      *
@@ -318,144 +223,25 @@
                       .map(dependencyUsage)
                       .collect(toImmutableList()))
               .build();
-      ClassName enclosingClass = membersInjectorNameForType(injectionSite.enclosingTypeElement());
-      MethodSpec methodSpec = create(injectionSite);
-      return invokeMethod(methodSpec, arguments, enclosingClass, generatedTypeName);
+      ClassName enclosingClass =
+          toJavaPoet(membersInjectorNameForType(injectionSite.enclosingTypeElement()));
+      String methodName = membersInjectorMethodName(injectionSite);
+      return invokeMethod(methodName, arguments, enclosingClass, generatedTypeName);
     }
-
-    /*
-     * TODO(ronshapiro): this isn't perfect, as collisions could still exist. Some examples:
-     *
-     *  - @Inject void members() {} will generate a method that conflicts with the instance
-     *    method `injectMembers(T)`
-     *  - Adding the index could conflict with another member:
-     *      @Inject void a(Object o) {}
-     *      @Inject void a(String s) {}
-     *      @Inject void a1(String s) {}
-     *
-     *    Here, Method a(String) will add the suffix "1", which will conflict with the method
-     *    generated for a1(String)
-     *  - Members named "members" or "methods" could also conflict with the {@code static} injection
-     *    method.
-     */
-    private static String methodName(InjectionSite injectionSite) {
-      int index = injectionSite.indexAmongAtInjectMembersWithSameSimpleName();
-      String indexString = index == 0 ? "" : String.valueOf(index + 1);
-      return "inject"
-          + LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(injectionSite.element()))
-          + indexString;
-    }
-  }
-
-  private enum InstanceCastPolicy {
-    CAST_IF_NOT_PUBLIC, IGNORE;
-
-    boolean useObjectType(XType instanceType) {
-      return this == CAST_IF_NOT_PUBLIC && !isRawTypePubliclyAccessible(instanceType);
-    }
-  }
-
-  private enum CheckNotNullPolicy {
-    IGNORE, CHECK_FOR_NULL;
-
-    CodeBlock checkForNull(CodeBlock maybeNull) {
-      return this.equals(IGNORE)
-          ? maybeNull
-          : CodeBlock.of("$T.checkNotNullFromProvides($L)", Preconditions.class, maybeNull);
-    }
-
-    static CheckNotNullPolicy get(ProvisionBinding binding, CompilerOptions compilerOptions) {
-      return binding.shouldCheckForNull(compilerOptions) ? CHECK_FOR_NULL : IGNORE;
-    }
-  }
-
-  private static MethodSpec methodProxy(
-      XMethodElement method,
-      String methodName,
-      InstanceCastPolicy instanceCastPolicy,
-      CheckNotNullPolicy checkNotNullPolicy) {
-    XTypeElement enclosingType = asTypeElement(method.getEnclosingElement());
-
-    MethodSpec.Builder builder =
-        methodBuilder(methodName)
-            .addModifiers(PUBLIC, STATIC)
-            .varargs(method.isVarArgs())
-            .addTypeVariables(method.getExecutableType().getTypeVariableNames());
-
-    UniqueNameSet parameterNameSet = new UniqueNameSet();
-    CodeBlock instance;
-    if (method.isStatic() || enclosingType.isCompanionObject()) {
-      instance = CodeBlock.of("$T", rawTypeName(enclosingType.getType().getTypeName()));
-    } else if (enclosingType.isKotlinObject()) {
-      // Call through the singleton instance.
-      // See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
-      instance = CodeBlock.of("$T.INSTANCE", rawTypeName(enclosingType.getType().getTypeName()));
-    } else {
-      builder.addTypeVariables(typeVariableNames(enclosingType));
-      boolean useObject = instanceCastPolicy.useObjectType(enclosingType.getType());
-      instance = copyInstance(builder, parameterNameSet, enclosingType.getType(), useObject);
-    }
-    CodeBlock arguments = copyParameters(builder, parameterNameSet, method.getParameters());
-    CodeBlock invocation =
-        checkNotNullPolicy.checkForNull(
-            CodeBlock.of("$L.$L($L)", instance, method.getJvmName(), arguments));
-
-    copyThrows(builder, method);
-
-    if (isVoid(method.getReturnType())) {
-      return builder.addStatement("$L", invocation).build();
-    } else {
-      Nullability nullability = Nullability.of(method);
-      nullability
-          .nullableAnnotations()
-          .forEach(builder::addAnnotation);
-      return builder
-          .returns(method.getReturnType().getTypeName())
-          .addStatement("return $L", invocation)
-          .build();
-    }
-  }
-
-  private static MethodSpec fieldProxy(
-      XFieldElement field, String methodName, Optional<XAnnotation> qualifier) {
-    XTypeElement enclosingType = asTypeElement(field.getEnclosingElement());
-
-    MethodSpec.Builder builder =
-        methodBuilder(methodName)
-            .addModifiers(PUBLIC, STATIC)
-            .addAnnotation(
-                AnnotationSpec.builder(TypeNames.INJECTED_FIELD_SIGNATURE)
-                    .addMember("value", "$S", memberInjectedFieldSignatureForVariable(field))
-                    .build())
-            .addTypeVariables(typeVariableNames(enclosingType));
-
-    qualifier.map(XAnnotations::getAnnotationSpec).ifPresent(builder::addAnnotation);
-
-    boolean useObject = !isRawTypePubliclyAccessible(enclosingType.getType());
-    UniqueNameSet parameterNameSet = new UniqueNameSet();
-    CodeBlock instance =
-        copyInstance(builder, parameterNameSet, enclosingType.getType(), useObject);
-    CodeBlock argument = copyParameters(builder, parameterNameSet, ImmutableList.of(field));
-    return builder.addStatement("$L.$L = $L", instance, getSimpleName(field), argument).build();
   }
 
   private static CodeBlock invokeMethod(
-      MethodSpec methodSpec,
+      String methodName,
       ImmutableList<CodeBlock> parameters,
       ClassName enclosingClass,
       ClassName requestingClass) {
-    checkArgument(methodSpec.parameters.size() == parameters.size());
     CodeBlock parameterBlock = makeParametersCodeBlock(parameters);
     return enclosingClass.equals(requestingClass)
-        ? CodeBlock.of("$L($L)", methodSpec.name, parameterBlock)
-        : CodeBlock.of("$T.$L($L)", enclosingClass, methodSpec.name, parameterBlock);
+        ? CodeBlock.of("$L($L)", methodName, parameterBlock)
+        : CodeBlock.of("$T.$L($L)", enclosingClass, methodName, parameterBlock);
   }
 
-  private static void copyThrows(MethodSpec.Builder methodBuilder, XExecutableElement method) {
-    method.getThrownTypes().stream().map(XType::getTypeName).forEach(methodBuilder::addException);
-  }
-
-  private static CodeBlock copyParameters(
+  static CodeBlock copyParameters(
       MethodSpec.Builder methodBuilder,
       UniqueNameSet parameterNameSet,
       List<? extends XVariableElement> parameters) {
@@ -468,26 +254,29 @@
                           ? asMethodParameter(parameter).getJvmName()
                           : getSimpleName(parameter));
               boolean useObject = !isRawTypePubliclyAccessible(parameter.getType());
-              return copyParameter(methodBuilder, parameter.getType(), name, useObject);
+              return copyParameter(
+                  methodBuilder, parameter.getType(), name, useObject, Nullability.of(parameter));
             })
         .collect(toParametersCodeBlock());
   }
 
-  private static CodeBlock copyParameter(
-      MethodSpec.Builder methodBuilder, XType type, String name, boolean useObject) {
-    TypeName typeName = useObject ? TypeName.OBJECT : type.getTypeName();
-    methodBuilder.addParameter(ParameterSpec.builder(typeName, name).build());
-    return useObject ? CodeBlock.of("($T) $L", type.getTypeName(), name) : CodeBlock.of("$L", name);
-  }
-
-  private static CodeBlock copyInstance(
+  static CodeBlock copyParameter(
       MethodSpec.Builder methodBuilder,
-      UniqueNameSet parameterNameSet,
       XType type,
-      boolean useObject) {
-    CodeBlock instance =
-        copyParameter(methodBuilder, type, parameterNameSet.getUniqueName("instance"), useObject);
-    // If we had to cast the instance add an extra parenthesis incase we're calling a method on it.
-    return useObject ? CodeBlock.of("($L)", instance) : instance;
+      String name,
+      boolean useObject,
+      Nullability nullability) {
+    TypeName typeName = useObject ? TypeName.OBJECT : type.getTypeName();
+    nullability.typeUseNullableAnnotations().stream()
+        .map(it -> AnnotationSpec.builder(it).build())
+        .forEach(typeName::annotated);
+    methodBuilder.addParameter(
+        ParameterSpec.builder(typeName, name)
+            .addAnnotations(
+                nullability.nonTypeUseNullableAnnotations().stream()
+                    .map(it -> AnnotationSpec.builder(it).build())
+                    .collect(toImmutableList()))
+            .build());
+    return useObject ? CodeBlock.of("($T) $L", type.getTypeName(), name) : CodeBlock.of("$L", name);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
index 27e017d..3d8fd86 100644
--- a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
@@ -66,7 +67,7 @@
 
   @Override
   public CodeBlock creationExpression() {
-    ClassName factoryImpl = generatedClassNameForBinding(binding);
+    ClassName factoryImpl = toJavaPoet(generatedClassNameForBinding(binding));
     CodeBlock createFactory =
         CodeBlock.of(
             "$T.$L($L)",
diff --git a/java/dagger/internal/codegen/writing/LazyClassKeyProviders.java b/java/dagger/internal/codegen/writing/LazyClassKeyProviders.java
deleted file mode 100644
index 2c25811..0000000
--- a/java/dagger/internal/codegen/writing/LazyClassKeyProviders.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2024 The Dagger 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
- *
- * 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 dagger.internal.codegen.writing;
-
-import static dagger.internal.codegen.base.MapKeyAccessibility.isMapKeyAccessibleFrom;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import androidx.room.compiler.processing.XAnnotation;
-import com.google.common.base.Preconditions;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.model.Key;
-import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import java.util.HashMap;
-import java.util.Map;
-
-/** Keeps track of all providers for DaggerMap keys. */
-public final class LazyClassKeyProviders {
-  public static final String MAP_KEY_PROVIDER_NAME = "LazyClassKeyProvider";
-  private final ClassName mapKeyProviderType;
-  private final Map<Key, FieldSpec> entries = new HashMap<>();
-  private final Map<Key, FieldSpec> keepClassNamesFields = new HashMap<>();
-  private final UniqueNameSet uniqueFieldNames = new UniqueNameSet();
-  private final ShardImplementation shardImplementation;
-  private boolean providerAdded = false;
-
-  LazyClassKeyProviders(ShardImplementation shardImplementation) {
-    String name = shardImplementation.getUniqueClassName(MAP_KEY_PROVIDER_NAME);
-    mapKeyProviderType = shardImplementation.name().nestedClass(name);
-    this.shardImplementation = shardImplementation;
-  }
-
-  /** Returns a reference to a field in LazyClassKeyProvider that corresponds to this binding. */
-  CodeBlock getMapKeyExpression(Key key) {
-    // This is for avoid generating empty LazyClassKeyProvider in codegen tests
-    if (!providerAdded) {
-      shardImplementation.addTypeSupplier(this::build);
-      providerAdded = true;
-    }
-    if (!entries.containsKey(key)) {
-      addField(key);
-    }
-    return CodeBlock.of("$T.$N", mapKeyProviderType, entries.get(key));
-  }
-
-  private void addField(Key key) {
-    Preconditions.checkArgument(
-        key.multibindingContributionIdentifier().isPresent()
-            && key.multibindingContributionIdentifier()
-                .get()
-                .bindingMethod()
-                .xprocessing()
-                .hasAnnotation(TypeNames.LAZY_CLASS_KEY));
-    XAnnotation lazyClassKeyAnnotation =
-        key.multibindingContributionIdentifier()
-            .get()
-            .bindingMethod()
-            .xprocessing()
-            .getAnnotation(TypeNames.LAZY_CLASS_KEY);
-    ClassName lazyClassKey =
-        lazyClassKeyAnnotation.getAsType("value").getTypeElement().getClassName();
-    entries.put(
-        key,
-        FieldSpec.builder(
-                TypeNames.STRING,
-                uniqueFieldNames.getUniqueName(lazyClassKey.canonicalName().replace('.', '_')))
-            // TODO(b/217435141): Leave the field as non-final. We will apply @IdentifierNameString
-            // on the field, which doesn't work well with static final fields.
-            .addModifiers(STATIC)
-            .initializer("$S", lazyClassKey.reflectionName())
-            .build());
-    // To be able to apply -includedescriptorclasses rule to keep the class names referenced by
-    // LazyClassKey, we need to generate fields that uses those classes as type in
-    // LazyClassKeyProvider. For types that are not accessible from the generated component, we
-    // generate fields in the proxy class.
-    // Note: the generated field should not be initialized to avoid class loading.
-    if (isMapKeyAccessibleFrom(lazyClassKeyAnnotation, shardImplementation.name().packageName())) {
-      keepClassNamesFields.put(
-          key,
-          FieldSpec.builder(
-                  lazyClassKey,
-                  uniqueFieldNames.getUniqueName(lazyClassKey.canonicalName().replace('.', '_')))
-              .addAnnotation(TypeNames.KEEP_FIELD_TYPE)
-              .build());
-    }
-  }
-
-  private TypeSpec build() {
-    TypeSpec.Builder builder =
-        TypeSpec.classBuilder(mapKeyProviderType)
-            .addAnnotation(TypeNames.IDENTIFIER_NAME_STRING)
-            .addModifiers(PRIVATE, STATIC, FINAL)
-            .addFields(entries.values())
-            .addFields(keepClassNamesFields.values());
-    return builder.build();
-  }
-}
diff --git a/java/dagger/internal/codegen/writing/LazyMapKeyProxyGenerator.java b/java/dagger/internal/codegen/writing/LazyMapKeyProxyGenerator.java
new file mode 100644
index 0000000..a5b15f2
--- /dev/null
+++ b/java/dagger/internal/codegen/writing/LazyMapKeyProxyGenerator.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.writing;
+
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.binding.MapKeys.KEEP_FIELD_TYPE_FIELD;
+import static dagger.internal.codegen.binding.MapKeys.LAZY_CLASS_KEY_NAME_FIELD;
+import static dagger.internal.codegen.binding.MapKeys.lazyClassKeyProxyClassName;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.base.SourceFileGenerator;
+import dagger.internal.codegen.javapoet.TypeNames;
+import javax.inject.Inject;
+
+/**
+ * Generate a class containing fields that works with proguard rules to support @LazyClassKey
+ * usages.
+ */
+public final class LazyMapKeyProxyGenerator extends SourceFileGenerator<XMethodElement> {
+
+  @Inject
+  LazyMapKeyProxyGenerator(XFiler filer, XProcessingEnv processingEnv) {
+    super(filer, processingEnv);
+  }
+
+  @Override
+  public XElement originatingElement(XMethodElement input) {
+    return input;
+  }
+
+  @Override
+  public ImmutableList<TypeSpec.Builder> topLevelTypes(XMethodElement input) {
+    return ImmutableList.of(lazyClassKeyProxyTypeSpec(input).toBuilder());
+  }
+
+  private TypeSpec lazyClassKeyProxyTypeSpec(XMethodElement element) {
+    return classBuilder(lazyClassKeyProxyClassName(element))
+        .addModifiers(PUBLIC, FINAL)
+        .addAnnotation(TypeNames.IDENTIFIER_NAME_STRING)
+        .addFields(lazyClassKeyFields(element))
+        .build();
+  }
+
+  private static ImmutableList<FieldSpec> lazyClassKeyFields(XMethodElement element) {
+    ClassName lazyClassMapKeyClassName =
+        element
+            .getAnnotation(TypeNames.LAZY_CLASS_KEY)
+            .getAsType("value")
+            .getTypeElement()
+            .getClassName();
+    // Generate a string referencing the map key class name, and dagger will apply
+    // identifierrnamestring rule to it to make sure it is correctly obfuscated.
+    FieldSpec lazyClassKeyField =
+        FieldSpec.builder(TypeNames.STRING, LAZY_CLASS_KEY_NAME_FIELD)
+            // TODO(b/217435141): Leave the field as non-final. We will apply
+            // @IdentifierNameString on the field, which doesn't work well with static final
+            // fields.
+            .addModifiers(STATIC, PUBLIC)
+            .initializer("$S", lazyClassMapKeyClassName.reflectionName())
+            .build();
+    // In proguard, we need to keep the classes referenced by @LazyClassKey, we do that by
+    // generating a field referencing the type, and then applying @KeepFieldType to the
+    // field. Here, we generate the field in the proxy class. For classes that are
+    // accessible from the dagger component, we generate fields in LazyClassKeyProvider.
+    // Note: the generated field should not be initialized to avoid class loading.
+    FieldSpec keepFieldTypeField =
+        FieldSpec.builder(lazyClassMapKeyClassName, KEEP_FIELD_TYPE_FIELD)
+            .addModifiers(STATIC)
+            .addAnnotation(TypeNames.KEEP_FIELD_TYPE)
+            .build();
+    return ImmutableList.of(keepFieldTypeField, lazyClassKeyField);
+  }
+}
diff --git a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
index 0ea382d..0ac7212 100644
--- a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
@@ -16,10 +16,11 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.binding.MapKeys.getLazyClassMapKeyExpression;
 import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
 import static dagger.internal.codegen.binding.SourceFiles.mapFactoryClassName;
-import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
 
 import androidx.room.compiler.processing.XProcessingEnv;
 import com.squareup.javapoet.ClassName;
@@ -32,9 +33,9 @@
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.MapKeys;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
-import java.util.stream.Stream;
 
 /** A factory creation expression for a multibound map. */
 final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpression {
@@ -42,13 +43,12 @@
   private final XProcessingEnv processingEnv;
   private final ComponentImplementation componentImplementation;
   private final BindingGraph graph;
-  private final ContributionBinding binding;
+  private final MultiboundMapBinding binding;
   private final boolean useLazyClassKey;
-  private final LazyClassKeyProviders lazyClassKeyProviders;
 
   @AssistedInject
   MapFactoryCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted MultiboundMapBinding binding,
       XProcessingEnv processingEnv,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations,
@@ -59,26 +59,16 @@
     this.componentImplementation = componentImplementation;
     this.graph = graph;
     this.useLazyClassKey = MapKeys.useLazyClassKey(binding, graph);
-    this.lazyClassKeyProviders =
-        componentImplementation.shardImplementation(binding).getLazyClassKeyProviders();
   }
 
   @Override
   public CodeBlock creationExpression() {
-    ClassName mapFactoryClassName = mapFactoryClassName(binding);
+    ClassName mapFactoryClassName = toJavaPoet(mapFactoryClassName(binding));
     CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName);
     TypeName valueTypeName = TypeName.OBJECT;
     if (!useRawType()) {
       MapType mapType = MapType.from(binding.key());
-      // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
-      // mapType.unwrappedValueType() method that doesn't require a framework type
-      valueTypeName =
-          Stream.of(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED)
-              .filter(mapType::valuesAreTypeOf)
-              .map(mapType::unwrappedValueType)
-              .collect(toOptional())
-              .orElseGet(mapType::valueType)
-              .getTypeName();
+      valueTypeName = mapType.unwrappedFrameworkValueType().getTypeName();
       builder.add(
           "<$T, $T>",
           useLazyClassKey ? TypeNames.STRING : mapType.keyType().getTypeName(),
@@ -92,7 +82,7 @@
       builder.add(
           ".put($L, $L)",
           useLazyClassKey
-              ? lazyClassKeyProviders.getMapKeyExpression(dependency.key())
+              ? getLazyClassMapKeyExpression(graph.contributionBinding(dependency.key()))
               : getMapKeyExpression(
                   contributionBinding, componentImplementation.name(), processingEnv),
           multibindingDependencyExpression(dependency));
@@ -101,14 +91,32 @@
     return useLazyClassKey
         ? CodeBlock.of(
             "$T.<$T>of($L)",
-            TypeNames.LAZY_CLASS_KEY_MAP_FACTORY,
+            lazyMapFactoryClassName(binding),
             valueTypeName,
             builder.add(".build()").build())
         : builder.add(".build()").build();
   }
 
+  private static ClassName lazyMapFactoryClassName(MultiboundMapBinding binding) {
+    MapType mapType = MapType.from(binding.key());
+    switch (binding.bindingType()) {
+      case PROVISION:
+        return mapType.valuesAreTypeOf(TypeNames.PROVIDER)
+            ? TypeNames.LAZY_CLASS_KEY_MAP_PROVIDER_FACTORY
+            : TypeNames.LAZY_CLASS_KEY_MAP_FACTORY;
+      case PRODUCTION:
+        return mapType.valuesAreFrameworkType()
+            ? mapType.valuesAreTypeOf(TypeNames.PRODUCER)
+                ? TypeNames.LAZY_MAP_OF_PRODUCER_PRODUCER
+                : TypeNames.LAZY_MAP_OF_PRODUCED_PRODUCER
+            : TypeNames.LAZY_MAP_PRODUCER;
+      default:
+        throw new IllegalArgumentException(binding.bindingType().toString());
+    }
+  }
+
   @AssistedFactory
   static interface Factory {
-    MapFactoryCreationExpression create(ContributionBinding binding);
+    MapFactoryCreationExpression create(MultiboundMapBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/MapRequestRepresentation.java b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
index f631d34..a870f66 100644
--- a/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
@@ -19,6 +19,7 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.binding.MapKeys.getLazyClassMapKeyExpression;
 import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
 import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
@@ -39,7 +40,7 @@
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.MapKeys;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.BindingKind;
@@ -52,15 +53,14 @@
   private static final int MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS = 5;
 
   private final XProcessingEnv processingEnv;
-  private final ProvisionBinding binding;
+  private final MultiboundMapBinding binding;
   private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
   private final ComponentRequestRepresentations componentRequestRepresentations;
   private final boolean useLazyClassKey;
-  private final LazyClassKeyProviders lazyClassKeyProviders;
 
   @AssistedInject
   MapRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted MultiboundMapBinding binding,
       XProcessingEnv processingEnv,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
@@ -73,8 +73,6 @@
     this.dependencies =
         Maps.toMap(binding.dependencies(), dep -> graph.contributionBinding(dep.key()));
     this.useLazyClassKey = MapKeys.useLazyClassKey(binding, graph);
-    this.lazyClassKeyProviders =
-        componentImplementation.shardImplementation(binding).getLazyClassKeyProviders();
   }
 
   @Override
@@ -153,7 +151,7 @@
     return CodeBlock.of(
         "$L, $L",
         useLazyClassKey
-            ? lazyClassKeyProviders.getMapKeyExpression(dependency.key())
+            ? getLazyClassMapKeyExpression(dependencies.get(dependency))
             : getMapKeyExpression(dependencies.get(dependency), requestingClass, processingEnv),
         componentRequestRepresentations
             .getDependencyExpression(bindingRequest(dependency), requestingClass)
@@ -194,6 +192,6 @@
 
   @AssistedFactory
   static interface Factory {
-    MapRequestRepresentation create(ProvisionBinding binding);
+    MapRequestRepresentation create(MultiboundMapBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
index a00e367..f128de3 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
@@ -32,11 +32,12 @@
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingGraph;
+import dagger.internal.codegen.binding.InjectionBinding;
 import dagger.internal.codegen.binding.MembersInjectionBinding;
 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
@@ -91,7 +92,7 @@
   }
 
   private Expression injectMethodExpression(Binding binding) {
-    // TODO(wanyingd): move Switching Providers and injection methods to Shard classes to avoid
+    // TODO(bcorso): move Switching Providers and injection methods to Shard classes to avoid
     // exceeding component class constant pool limit.
     // Add to Component Shard so that is can be accessible from Switching Providers.
     ShardImplementation shardImplementation = componentImplementation.shardImplementation(binding);
@@ -105,7 +106,15 @@
     // simple names Foo.Builder -> injectFooBuilder
     String methodName = shardImplementation.getUniqueMethodName("inject" + bindingTypeName);
     ParameterSpec parameter =
-        ParameterSpec.builder(membersInjectedType.getTypeName(), "instance").build();
+        ParameterSpec.builder(
+                membersInjectedType.getTypeName(),
+                // Technically this usage only needs to be unique within this method, but this will
+                // allocate
+                // a unique name within the shard. We could optimize this by cloning the
+                // UniqueNameSet or
+                // using NameAllocator which has a clone method in the future.
+                shardImplementation.getUniqueFieldName("instance"))
+            .build();
     MethodSpec.Builder methodBuilder =
         methodBuilder(methodName)
             .addModifiers(PRIVATE)
@@ -135,11 +144,15 @@
   }
 
   private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
-    if (binding instanceof ProvisionBinding) {
-      return ((ProvisionBinding) binding).injectionSites();
-    } else if (binding instanceof MembersInjectionBinding) {
-      return ((MembersInjectionBinding) binding).injectionSites();
+    switch (binding.kind()) {
+      case INJECTION:
+        return ((InjectionBinding) binding).injectionSites();
+      case ASSISTED_INJECTION:
+        return ((AssistedInjectionBinding) binding).injectionSites();
+      case MEMBERS_INJECTION:
+        return ((MembersInjectionBinding) binding).injectionSites();
+      default:
+        throw new IllegalArgumentException("Unexpected binding kind: " + binding.kind());
     }
-    throw new IllegalArgumentException(binding.key().toString());
   }
 }
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java b/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java
index f8f31a3..a932a38 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionRequestRepresentation.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.processing.XTypeKt.isVoid;
 import static com.google.common.collect.Iterables.getOnlyElement;
 
 import androidx.room.compiler.processing.XExecutableParameterElement;
@@ -54,6 +55,15 @@
       ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
     XMethodElement methodElement = componentMethod.methodElement();
     XExecutableParameterElement parameter = getOnlyElement(methodElement.getParameters());
+    if (binding.injectionSites().isEmpty()) {
+      // If there are no injection sites either do nothing (if the return type is void) or return
+      // the input instance as-is.
+      return Expression.create(
+          methodElement.getReturnType(),
+          isVoid(methodElement.getReturnType())
+              ? CodeBlock.of("")
+              : CodeBlock.of("$L", parameter.getJvmName()));
+    }
     return membersInjectionMethods.getInjectExpression(
         binding.key(), CodeBlock.of("$L", parameter.getJvmName()), component.name());
   }
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
index 36a9915..1b52eb0 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
@@ -16,30 +16,52 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.compat.XConverters.toJavaPoet;
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static com.squareup.javapoet.TypeSpec.classBuilder;
 import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
 import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
+import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
+import static dagger.internal.codegen.binding.SourceFiles.membersInjectorMethodName;
 import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
 import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
 import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toConcatenatedCodeBlock;
 import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.writing.FactoryGenerator.hasDaggerProviderParams;
+import static dagger.internal.codegen.writing.FactoryGenerator.remapParamsToJavaxProvider;
+import static dagger.internal.codegen.writing.FactoryGenerator.wrappedParametersCodeBlock;
 import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.writing.InjectionMethods.copyParameter;
+import static dagger.internal.codegen.writing.InjectionMethods.copyParameters;
+import static dagger.internal.codegen.xprocessing.XElements.asField;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static javax.lang.model.element.Modifier.STATIC;
 
+import androidx.room.compiler.processing.XAnnotation;
 import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XFieldElement;
 import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.squareup.javapoet.AnnotationSpec;
@@ -54,7 +76,6 @@
 import dagger.MembersInjector;
 import dagger.internal.codegen.base.SourceFileGenerator;
 import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.FrameworkField;
 import dagger.internal.codegen.binding.MembersInjectionBinding;
 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
 import dagger.internal.codegen.binding.SourceFiles;
@@ -63,7 +84,10 @@
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import java.util.Map.Entry;
+import dagger.internal.codegen.xprocessing.Nullability;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import java.util.List;
+import java.util.Optional;
 import javax.inject.Inject;
 
 /**
@@ -95,115 +119,218 @@
         "tried to generate a MembersInjector for a binding of a resolved generic type: %s",
         binding);
 
-    ClassName generatedTypeName = membersInjectorNameForType(binding.membersInjectedType());
+    ClassName generatedTypeName =
+        toJavaPoet(membersInjectorNameForType(binding.membersInjectedType()));
     ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
+    ImmutableMap<DependencyRequest, FieldSpec> frameworkFields = frameworkFields(binding);
     TypeSpec.Builder injectorTypeBuilder =
         classBuilder(generatedTypeName)
             .addModifiers(PUBLIC, FINAL)
             .addTypeVariables(typeParameters)
-            .addAnnotation(qualifierMetadataAnnotation(binding));
-
-    TypeName injectedTypeName = binding.key().type().xprocessing().getTypeName();
-    TypeName implementedType = membersInjectorOf(injectedTypeName);
-    injectorTypeBuilder.addSuperinterface(implementedType);
-
-    MethodSpec.Builder injectMembersBuilder =
-        methodBuilder("injectMembers")
-            .addModifiers(PUBLIC)
-            .addAnnotation(Override.class)
-            .addParameter(injectedTypeName, "instance");
-
-    ImmutableMap<DependencyRequest, FrameworkField> fields =
-        generateBindingFieldsForDependencies(binding);
-
-    ImmutableMap.Builder<DependencyRequest, FieldSpec> dependencyFieldsBuilder =
-        ImmutableMap.builder();
-
-    MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PUBLIC);
-
-    // We use a static create method so that generated components can avoid having
-    // to refer to the generic types of the factory.
-    // (Otherwise they may have visibility problems referring to the types.)
-    MethodSpec.Builder createMethodBuilder =
-        methodBuilder("create")
-            .returns(implementedType)
-            .addModifiers(PUBLIC, STATIC)
-            .addTypeVariables(typeParameters);
-
-    createMethodBuilder.addCode(
-        "return new $T(", parameterizedGeneratedTypeNameForBinding(binding));
-    ImmutableList.Builder<CodeBlock> constructorInvocationParameters = ImmutableList.builder();
-
-    boolean usesRawFrameworkTypes = false;
-    UniqueNameSet fieldNames = new UniqueNameSet();
-    for (Entry<DependencyRequest, FrameworkField> fieldEntry : fields.entrySet()) {
-      DependencyRequest dependency = fieldEntry.getKey();
-      FrameworkField bindingField = fieldEntry.getValue();
-
-      // If the dependency type is not visible to this members injector, then use the raw framework
-      // type for the field.
-      boolean useRawFrameworkType =
-          !isTypeAccessibleFrom(
-              dependency.key().type().xprocessing(), generatedTypeName.packageName());
-
-      String fieldName = fieldNames.getUniqueName(bindingField.name());
-      TypeName fieldType = useRawFrameworkType
-          ? TypeNames.rawTypeName(bindingField.type())
-          : bindingField.type();
-      FieldSpec.Builder fieldBuilder = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL);
-      ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(fieldType, fieldName);
-
-      // If we're using the raw type for the field, then suppress the injectMembers method's
-      // unchecked-type warning and the field's and the constructor and create-method's
-      // parameters' raw-type warnings.
-      if (useRawFrameworkType) {
-        usesRawFrameworkTypes = true;
-        fieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
-        parameterBuilder.addAnnotation(suppressWarnings(RAWTYPES));
-      }
-      constructorBuilder.addParameter(parameterBuilder.build());
-      createMethodBuilder.addParameter(parameterBuilder.build());
-
-      FieldSpec field = fieldBuilder.build();
-      injectorTypeBuilder.addField(field);
-      constructorBuilder.addStatement("this.$1N = $1N", field);
-      dependencyFieldsBuilder.put(dependency, field);
-      constructorInvocationParameters.add(CodeBlock.of("$N", field));
-    }
-
-    createMethodBuilder.addCode(
-        constructorInvocationParameters.build().stream().collect(toParametersCodeBlock()));
-    createMethodBuilder.addCode(");");
-
-    injectorTypeBuilder.addMethod(constructorBuilder.build());
-    injectorTypeBuilder.addMethod(createMethodBuilder.build());
-
-    ImmutableMap<DependencyRequest, FieldSpec> dependencyFields = dependencyFieldsBuilder.build();
-
-    injectMembersBuilder.addCode(
-        InjectionSiteMethod.invokeAll(
-            binding.injectionSites(),
-            generatedTypeName,
-            CodeBlock.of("instance"),
-            binding.key().type().xprocessing(),
-            sourceFiles.frameworkFieldUsages(binding.dependencies(), dependencyFields)::get));
-
-    if (usesRawFrameworkTypes) {
-      injectMembersBuilder.addAnnotation(suppressWarnings(UNCHECKED));
-    }
-    injectorTypeBuilder.addMethod(injectMembersBuilder.build());
-
-    for (InjectionSite injectionSite : binding.injectionSites()) {
-      if (injectionSite.enclosingTypeElement().equals(binding.membersInjectedType())) {
-        injectorTypeBuilder.addMethod(InjectionSiteMethod.create(injectionSite));
-      }
-    }
+            .addAnnotation(qualifierMetadataAnnotation(binding))
+            .addSuperinterface(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
+            .addFields(frameworkFields.values())
+            .addMethod(constructor(frameworkFields))
+            .addMethods(createMethod(binding, frameworkFields))
+            .addMethod(injectMembersMethod(binding, frameworkFields))
+            .addMethods(
+                binding.injectionSites().stream()
+                    .filter(
+                        site -> site.enclosingTypeElement().equals(binding.membersInjectedType()))
+                    .map(MembersInjectorGenerator::membersInjectionMethod)
+                    .collect(toImmutableList()));
 
     gwtIncompatibleAnnotation(binding).ifPresent(injectorTypeBuilder::addAnnotation);
 
     return ImmutableList.of(injectorTypeBuilder);
   }
 
+  private static MethodSpec membersInjectionMethod(InjectionSite injectionSite) {
+    String methodName = membersInjectorMethodName(injectionSite);
+    switch (injectionSite.kind()) {
+      case METHOD:
+        return methodInjectionMethod(asMethod(injectionSite.element()), methodName);
+      case FIELD:
+        Optional<XAnnotation> qualifier =
+            // methods for fields have a single dependency request
+            getOnlyElement(injectionSite.dependencies())
+                .key()
+                .qualifier()
+                .map(DaggerAnnotation::xprocessing);
+        return fieldInjectionMethod(asField(injectionSite.element()), methodName, qualifier);
+    }
+    throw new AssertionError(injectionSite);
+  }
+
+  // Example:
+  //
+  // public static void injectMethod(Instance instance, Foo foo, Bar bar) {
+  //   instance.injectMethod(foo, bar);
+  // }
+  private static MethodSpec methodInjectionMethod(XMethodElement method, String methodName) {
+    XTypeElement enclosingType = asTypeElement(method.getEnclosingElement());
+    MethodSpec.Builder builder =
+        methodBuilder(methodName)
+            .addModifiers(PUBLIC, STATIC)
+            .varargs(method.isVarArgs())
+            .addTypeVariables(typeVariableNames(enclosingType))
+            .addExceptions(getThrownTypes(method));
+
+    UniqueNameSet parameterNameSet = new UniqueNameSet();
+    CodeBlock instance = copyInstance(builder, parameterNameSet, enclosingType.getType());
+    CodeBlock arguments = copyParameters(builder, parameterNameSet, method.getParameters());
+    return builder.addStatement("$L.$L($L)", instance, method.getJvmName(), arguments).build();
+  }
+
+  // Example:
+  //
+  // public static void injectFoo(Instance instance, Foo foo) {
+  //   instance.foo = foo;
+  // }
+  private static MethodSpec fieldInjectionMethod(
+      XFieldElement field, String methodName, Optional<XAnnotation> qualifier) {
+    XTypeElement enclosingType = asTypeElement(field.getEnclosingElement());
+
+    MethodSpec.Builder builder =
+        methodBuilder(methodName)
+            .addModifiers(PUBLIC, STATIC)
+            .addAnnotation(
+                AnnotationSpec.builder(TypeNames.INJECTED_FIELD_SIGNATURE)
+                    .addMember("value", "$S", memberInjectedFieldSignatureForVariable(field))
+                    .build())
+            .addTypeVariables(typeVariableNames(enclosingType));
+
+    qualifier.map(XAnnotations::getAnnotationSpec).ifPresent(builder::addAnnotation);
+
+    UniqueNameSet parameterNameSet = new UniqueNameSet();
+    CodeBlock instance = copyInstance(builder, parameterNameSet, enclosingType.getType());
+    CodeBlock argument = copyParameters(builder, parameterNameSet, ImmutableList.of(field));
+    return builder.addStatement("$L.$L = $L", instance, getSimpleName(field), argument).build();
+  }
+
+  private static ImmutableList<TypeName> getThrownTypes(XExecutableElement executable) {
+    return executable.getThrownTypes().stream().map(XType::getTypeName).collect(toImmutableList());
+  }
+
+  private static CodeBlock copyInstance(
+      MethodSpec.Builder methodBuilder, UniqueNameSet parameterNameSet, XType type) {
+    boolean useObject = !isRawTypePubliclyAccessible(type);
+    CodeBlock instance =
+        copyParameter(
+            methodBuilder,
+            type,
+            parameterNameSet.getUniqueName("instance"),
+            useObject,
+            Nullability.NOT_NULLABLE);
+    // If we had to cast the instance add an extra parenthesis incase we're calling a method on it.
+    return useObject ? CodeBlock.of("($L)", instance) : instance;
+  }
+
+  // MyClass(
+  //     Provider<Dep1> dep1Provider,
+  //     Provider<Dep2> dep2Provider,
+  //     // Note: The raw type can happen if Dep3 is injected in a super type and not accessible to
+  //     // the parent. Ideally, we would have passed in the parent MembersInjector instance itself
+  //     // which would have avoided this situation, but doing it now would cause version skew.
+  //     @SuppressWarnings("RAW_TYPE") Provider dep3Provider) {
+  //   this.dep1Provider = dep1Provider;
+  //   this.dep2Provider = dep2Provider;
+  //   this.dep3Provider = dep3Provider;
+  // }
+  private MethodSpec constructor(ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
+    ImmutableList<ParameterSpec> dependencyParameters =
+        frameworkFields.values().stream()
+            .map(
+                field ->
+                    ParameterSpec.builder(field.type, field.name)
+                        .addAnnotations(field.annotations)
+                        .build())
+            .collect(toImmutableList());
+    return constructorBuilder()
+        .addModifiers(PUBLIC)
+        .addParameters(dependencyParameters)
+        .addCode(
+            dependencyParameters.stream()
+                .map(parameter -> CodeBlock.of("this.$1N = $1N;", parameter))
+                .collect(toConcatenatedCodeBlock()))
+        .build();
+  }
+
+  // public static MyClass_MembersInjector create(
+  //     Provider<Dep1> dep1Provider,
+  //     Provider<Dep2> dep2Provider,
+  //     // Note: The raw type can happen if Dep3 is injected in a super type and not accessible to
+  //     // the parent. Ideally, we would have passed in the parent MembersInjector instance itself
+  //     // which would have avoided this situation, but doing it now would cause version skew.
+  //     @SuppressWarnings("RAW_TYPE") Provider dep3Provider) {
+  //   return new MyClass_MembersInjector(dep1Provider, dep2Provider, dep3Provider);
+  // }
+  private ImmutableList<MethodSpec> createMethod(
+      MembersInjectionBinding binding,
+      ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
+    ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
+    List<ParameterSpec> params = constructor(frameworkFields).parameters;
+    // We use a static create method so that generated components can avoid having
+    // to refer to the generic types of the factory.
+    // (Otherwise they may have visibility problems referring to the types.)
+    methodsBuilder.add(methodBuilder("create")
+        .addModifiers(PUBLIC, STATIC)
+        .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+        .returns(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
+        .addParameters(params)
+        .addStatement(
+            "return new $T($L)",
+            parameterizedGeneratedTypeNameForBinding(binding),
+            parameterNames(params))
+        .build());
+    if (hasDaggerProviderParams(params)) {
+      methodsBuilder.add(javaxCreateMethod(binding, params));
+    }
+    return methodsBuilder.build();
+  }
+
+  private MethodSpec javaxCreateMethod(
+      MembersInjectionBinding binding, List<ParameterSpec> params) {
+    ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(params);
+    return methodBuilder("create")
+        .addModifiers(PUBLIC, STATIC)
+        .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+        .returns(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
+        .addParameters(remappedParams)
+        .addStatement(
+            "return new $T($L)",
+            parameterizedGeneratedTypeNameForBinding(binding),
+            wrappedParametersCodeBlock(remappedParams))
+        .build();
+  }
+
+  // @Override
+  // public void injectMembers(Thing instance) {
+  //   injectDep1(instance, dep1Provider.get());
+  //   injectSomeMethod(instance, dep2Provider.get());
+  //   // This is a case where Dep3 is injected in the base class.
+  //   MyBaseClass_MembersInjector.injectDep3(instance, dep3Provider.get());
+  // }
+  private MethodSpec injectMembersMethod(
+      MembersInjectionBinding binding,
+      ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
+    XType instanceType = binding.key().type().xprocessing();
+    ImmutableMap<DependencyRequest, CodeBlock> dependencyCodeBlocks =
+        sourceFiles.frameworkFieldUsages(binding.dependencies(), frameworkFields);
+    return methodBuilder("injectMembers")
+        .addModifiers(PUBLIC)
+        .addAnnotation(Override.class)
+        .addParameter(instanceType.getTypeName(), "instance")
+        .addCode(
+            InjectionSiteMethod.invokeAll(
+                binding.injectionSites(),
+                toJavaPoet(membersInjectorNameForType(binding.membersInjectedType())),
+                CodeBlock.of("instance"),
+                instanceType,
+                dependencyCodeBlocks::get))
+        .build();
+  }
+
   private AnnotationSpec qualifierMetadataAnnotation(MembersInjectionBinding binding) {
     AnnotationSpec.Builder builder = AnnotationSpec.builder(TypeNames.QUALIFIER_METADATA);
     binding.injectionSites().stream()
@@ -222,4 +349,35 @@
         .forEach(qualifier -> builder.addMember("value", "$S", qualifier));
     return builder.build();
   }
+
+  private static ImmutableMap<DependencyRequest, FieldSpec> frameworkFields(
+      MembersInjectionBinding binding) {
+    UniqueNameSet fieldNames = new UniqueNameSet();
+    ClassName membersInjectorTypeName =
+        toJavaPoet(membersInjectorNameForType(binding.membersInjectedType()));
+    ImmutableMap.Builder<DependencyRequest, FieldSpec> builder = ImmutableMap.builder();
+    generateBindingFieldsForDependencies(binding)
+        .forEach(
+            (request, bindingField) -> {
+              // If the dependency type is not visible to this members injector, then use the raw
+              // framework type for the field.
+              boolean useRawFrameworkType =
+                  !isTypeAccessibleFrom(
+                      request.key().type().xprocessing(),
+                      membersInjectorTypeName.packageName());
+              TypeName fieldType =
+                  useRawFrameworkType
+                      ? toJavaPoet(bindingField.type().getRawTypeName())
+                      : toJavaPoet(bindingField.type());
+              String fieldName = fieldNames.getUniqueName(bindingField.name());
+              FieldSpec field =
+                  useRawFrameworkType
+                      ? FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL)
+                          .addAnnotation(suppressWarnings(RAWTYPES))
+                          .build()
+                      : FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL).build();
+              builder.put(request, field);
+            });
+    return builder.buildOrThrow();
+  }
 }
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java b/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
index e6906ea..5b9d348 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
@@ -29,7 +30,7 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.MembersInjectorBinding;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 
@@ -39,11 +40,11 @@
 
   private final ShardImplementation shardImplementation;
   private final ComponentRequestRepresentations componentRequestRepresentations;
-  private final ProvisionBinding binding;
+  private final MembersInjectorBinding binding;
 
   @AssistedInject
   MembersInjectorProviderCreationExpression(
-      @Assisted ProvisionBinding binding,
+      @Assisted MembersInjectorBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations) {
     this.binding = checkNotNull(binding);
@@ -73,7 +74,7 @@
       membersInjector =
           CodeBlock.of(
               "$T.create($L)",
-              membersInjectorNameForType(injectedTypeElement),
+              toJavaPoet(membersInjectorNameForType(injectedTypeElement)),
               componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
                   binding, shardImplementation.name()));
     }
@@ -100,6 +101,6 @@
 
   @AssistedFactory
   static interface Factory {
-    MembersInjectorProviderCreationExpression create(ProvisionBinding binding);
+    MembersInjectorProviderCreationExpression create(MembersInjectorBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ModuleProxies.java b/java/dagger/internal/codegen/writing/ModuleProxies.java
index eaf57ee..772cc63 100644
--- a/java/dagger/internal/codegen/writing/ModuleProxies.java
+++ b/java/dagger/internal/codegen/writing/ModuleProxies.java
@@ -16,9 +16,11 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
 import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.binding.SourceFiles.classFileName;
 import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
 import static dagger.internal.codegen.xprocessing.XTypeElements.isNested;
 import static javax.lang.model.element.Modifier.FINAL;
@@ -26,6 +28,7 @@
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static javax.lang.model.element.Modifier.STATIC;
 
+import androidx.room.compiler.codegen.XClassName;
 import androidx.room.compiler.processing.XConstructorElement;
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XFiler;
@@ -37,7 +40,6 @@
 import com.squareup.javapoet.TypeSpec;
 import dagger.internal.codegen.base.ModuleKind;
 import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.SourceFiles;
 import dagger.internal.codegen.langmodel.Accessibility;
 import java.util.Optional;
 import javax.inject.Inject;
@@ -86,10 +88,10 @@
   /** The name of the class that hosts the module constructor proxy method. */
   private static ClassName constructorProxyTypeName(XTypeElement moduleElement) {
     ModuleKind.checkIsModule(moduleElement);
-    ClassName moduleClassName = moduleElement.getClassName();
-    return moduleClassName
+    XClassName moduleClassName = moduleElement.asClassName();
+    return toJavaPoet(moduleClassName)
         .topLevelClassName()
-        .peerClass(SourceFiles.classFileName(moduleClassName) + "_Proxy");
+        .peerClass(classFileName(moduleClassName) + "_Proxy");
   }
 
   /**
diff --git a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
index 5cb47bb..667fe08 100644
--- a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.squareup.javapoet.CodeBlock;
@@ -52,7 +53,7 @@
             .codeBlock();
 
     return useRawType()
-        ? CodeBlocks.cast(expression, binding.frameworkType().frameworkClassName())
+        ? CodeBlocks.cast(expression, toJavaPoet(binding.frameworkType().frameworkClassName()))
         : expression;
   }
 
diff --git a/java/dagger/internal/codegen/writing/OptionalFactories.java b/java/dagger/internal/codegen/writing/OptionalFactories.java
index 3c327e8..fc31989 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactories.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactories.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
 import static com.google.common.base.Verify.verify;
@@ -57,8 +58,8 @@
 import dagger.internal.codegen.base.OptionalType;
 import dagger.internal.codegen.base.OptionalType.OptionalKind;
 import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.FrameworkType;
+import dagger.internal.codegen.binding.OptionalBinding;
 import dagger.internal.codegen.javapoet.AnnotationSpecs;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.RequestKind;
@@ -119,7 +120,7 @@
    * Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
    * for absent optional bindings.
    */
-  CodeBlock absentOptionalProvider(ContributionBinding binding) {
+  CodeBlock absentOptionalProvider(OptionalBinding binding) {
     verify(
         binding.bindingType().equals(BindingType.PROVISION),
         "Absent optional bindings should be provisions: %s",
@@ -267,11 +268,11 @@
       return new StringBuilder("Present")
           .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind().name()))
           .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind().toString()))
-          .append(frameworkType().frameworkClassName().simpleName())
+          .append(toJavaPoet(frameworkType().frameworkClassName()).simpleName())
           .toString();
     }
 
-    private static PresentFactorySpec of(ContributionBinding binding) {
+    private static PresentFactorySpec of(OptionalBinding binding) {
       return new AutoValue_OptionalFactories_PresentFactorySpec(
           FrameworkType.forBindingType(binding.bindingType()),
           OptionalType.from(binding.key()).kind(),
@@ -302,7 +303,7 @@
    * @param delegateFactory an expression for a {@code Provider} or {@code Producer} of the
    *     underlying type
    */
-  CodeBlock presentOptionalFactory(ContributionBinding binding, CodeBlock delegateFactory) {
+  CodeBlock presentOptionalFactory(OptionalBinding binding, CodeBlock delegateFactory) {
     return CodeBlock.of(
         "$N.of($L)",
         perGeneratedFileCache.presentFactoryClasses.computeIfAbsent(
diff --git a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
index 2f2ae58..0ff13a9 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
@@ -23,7 +23,7 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.OptionalBinding;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 
 /**
@@ -33,13 +33,13 @@
 final class OptionalFactoryInstanceCreationExpression
     implements FrameworkInstanceCreationExpression {
   private final OptionalFactories optionalFactories;
-  private final ContributionBinding binding;
+  private final OptionalBinding binding;
   private final ComponentImplementation componentImplementation;
   private final ComponentRequestRepresentations componentRequestRepresentations;
 
   @AssistedInject
   OptionalFactoryInstanceCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted OptionalBinding binding,
       OptionalFactories optionalFactories,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations) {
@@ -65,6 +65,6 @@
 
   @AssistedFactory
   static interface Factory {
-    OptionalFactoryInstanceCreationExpression create(ContributionBinding binding);
+    OptionalFactoryInstanceCreationExpression create(OptionalBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
index 8c92191..6d91f5b 100644
--- a/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
@@ -30,20 +30,20 @@
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.base.OptionalType;
 import dagger.internal.codegen.base.OptionalType.OptionalKind;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.OptionalBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.model.RequestKind;
 
 /** A binding expression for optional bindings. */
 final class OptionalRequestRepresentation extends RequestRepresentation {
-  private final ProvisionBinding binding;
+  private final OptionalBinding binding;
   private final ComponentRequestRepresentations componentRequestRepresentations;
   private final XProcessingEnv processingEnv;
 
   @AssistedInject
   OptionalRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted OptionalBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations,
       XProcessingEnv processingEnv) {
@@ -99,6 +99,6 @@
 
   @AssistedFactory
   static interface Factory {
-    OptionalRequestRepresentation create(ProvisionBinding binding);
+    OptionalRequestRepresentation create(OptionalBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
index 8e8c271..4f15f63 100644
--- a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
 
@@ -23,7 +24,7 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.ProductionBinding;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 
@@ -36,11 +37,11 @@
 
   private final ShardImplementation shardImplementation;
   private final ComponentRequestRepresentations componentRequestRepresentations;
-  private final ContributionBinding binding;
+  private final ProductionBinding binding;
 
   @AssistedInject
   ProducerCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted ProductionBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations) {
     this.binding = checkNotNull(binding);
@@ -52,13 +53,13 @@
   public CodeBlock creationExpression() {
     return CodeBlock.of(
         "$T.create($L)",
-        generatedClassNameForBinding(binding),
+        toJavaPoet(generatedClassNameForBinding(binding)),
         componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
             binding, shardImplementation.name()));
   }
 
   @AssistedFactory
   static interface Factory {
-    ProducerCreationExpression create(ContributionBinding binding);
+    ProducerCreationExpression create(ProductionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
index 1d8ab02..a588c2d 100644
--- a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
@@ -16,8 +16,9 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verifyNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.squareup.javapoet.ClassName.OBJECT;
 import static com.squareup.javapoet.MethodSpec.constructorBuilder;
 import static com.squareup.javapoet.MethodSpec.methodBuilder;
@@ -30,18 +31,21 @@
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.FUTURE_RETURN_VALUE_IGNORED;
 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
 import static dagger.internal.codegen.javapoet.TypeNames.FUTURES;
 import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
 import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_TOKEN;
 import static dagger.internal.codegen.javapoet.TypeNames.VOID_CLASS;
+import static dagger.internal.codegen.javapoet.TypeNames.isFutureType;
 import static dagger.internal.codegen.javapoet.TypeNames.listOf;
 import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
 import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
+import static dagger.internal.codegen.writing.FactoryGenerator.hasDaggerProviderParams;
+import static dagger.internal.codegen.writing.FactoryGenerator.remapParamsToJavaxProvider;
+import static dagger.internal.codegen.writing.FactoryGenerator.wrappedParametersCodeBlock;
 import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PROTECTED;
@@ -50,24 +54,24 @@
 
 import androidx.room.compiler.processing.XElement;
 import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XType;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
 import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.ParameterizedTypeName;
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.base.ContributionType;
+import dagger.internal.codegen.base.SetType;
 import dagger.internal.codegen.base.SourceFileGenerator;
 import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.binding.KeyFactory;
 import dagger.internal.codegen.binding.ProductionBinding;
 import dagger.internal.codegen.binding.SourceFiles;
 import dagger.internal.codegen.compileroption.CompilerOptions;
@@ -75,18 +79,14 @@
 import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
-import dagger.internal.codegen.model.Key;
 import dagger.internal.codegen.model.RequestKind;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map.Entry;
 import java.util.Optional;
 import javax.inject.Inject;
 
 /** Generates {@code Producer} implementations from {@link ProductionBinding} instances. */
 public final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
   private final CompilerOptions compilerOptions;
-  private final KeyFactory keyFactory;
   private final SourceFiles sourceFiles;
 
   @Inject
@@ -94,11 +94,9 @@
       XFiler filer,
       XProcessingEnv processingEnv,
       CompilerOptions compilerOptions,
-      KeyFactory keyFactory,
       SourceFiles sourceFiles) {
     super(filer, processingEnv);
     this.compilerOptions = compilerOptions;
-    this.keyFactory = keyFactory;
     this.sourceFiles = sourceFiles;
   }
 
@@ -114,173 +112,285 @@
     checkArgument(!binding.unresolved().isPresent());
     checkArgument(binding.bindingElement().isPresent());
 
-    TypeName providedTypeName = binding.contributedType().getTypeName();
-    TypeName futureTypeName = listenableFutureOf(providedTypeName);
-
-    ClassName generatedTypeName = generatedClassNameForBinding(binding);
+    FactoryFields factoryFields = FactoryFields.create(binding);
     TypeSpec.Builder factoryBuilder =
-        classBuilder(generatedTypeName)
+        classBuilder(toJavaPoet(generatedClassNameForBinding(binding)))
+            .superclass(
+                ParameterizedTypeName.get(
+                    TypeNames.ABSTRACT_PRODUCES_METHOD_PRODUCER,
+                    callProducesMethodParameter(binding).type,
+                    binding.contributedType().getTypeName()))
             .addModifiers(PUBLIC, FINAL)
-            .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
-
-    UniqueNameSet uniqueFieldNames = new UniqueNameSet();
-    ImmutableMap.Builder<DependencyRequest, FieldSpec> fieldsBuilder = ImmutableMap.builder();
-
-    MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PRIVATE);
-
-    Optional<FieldSpec> moduleField =
-        binding.requiresModuleInstance()
-            ? Optional.of(
-                addFieldAndConstructorParameter(
-                    factoryBuilder,
-                    constructorBuilder,
-                    uniqueFieldNames.getUniqueName("module"),
-                    binding.bindingTypeElement().get().getType().getTypeName()))
-            : Optional.empty();
-
-    List<CodeBlock> frameworkFieldAssignments = new ArrayList<>();
-
-    String executorParameterName = null;
-    String monitorParameterName = null;
-    ImmutableMap<DependencyRequest, FrameworkField> bindingFieldsForDependencies =
-        generateBindingFieldsForDependencies(binding);
-    for (Entry<DependencyRequest, FrameworkField> entry : bindingFieldsForDependencies.entrySet()) {
-      DependencyRequest dependency = entry.getKey();
-      Key key = dependency.key();
-      FrameworkField bindingField = entry.getValue();
-      String fieldName = uniqueFieldNames.getUniqueName(bindingField.name());
-      if (key.equals(keyFactory.forProductionImplementationExecutor())) {
-        executorParameterName = fieldName;
-        constructorBuilder.addParameter(bindingField.type(), executorParameterName);
-      } else if (key.equals(keyFactory.forProductionComponentMonitor())) {
-        monitorParameterName = fieldName;
-        constructorBuilder.addParameter(bindingField.type(), monitorParameterName);
-      } else {
-        FieldSpec field =
-            addFieldAndConstructorParameter(
-                factoryBuilder, constructorBuilder, fieldName, bindingField.type());
-        fieldsBuilder.put(dependency, field);
-        frameworkFieldAssignments.add(fieldAssignment(field, bindingField));
-      }
-    }
-    ImmutableMap<DependencyRequest, FieldSpec> fields = fieldsBuilder.build();
-
-    constructorBuilder.addStatement(
-        "super($N, $L, $N)",
-        verifyNotNull(monitorParameterName),
-        producerTokenConstruction(generatedTypeName, binding),
-        verifyNotNull(executorParameterName));
-
-    if (binding.requiresModuleInstance()) {
-      assignField(constructorBuilder, moduleField.get(), null);
-    }
-
-    constructorBuilder.addCode(CodeBlock.join(frameworkFieldAssignments, "\n"));
-
-    MethodSpec.Builder collectDependenciesBuilder =
-        methodBuilder("collectDependencies").addAnnotation(Override.class).addModifiers(PROTECTED);
-
-    ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
-    for (DependencyRequest dependency : asyncDependencies) {
-      TypeName futureType = listenableFutureOf(asyncDependencyType(dependency));
-      CodeBlock futureAccess = CodeBlock.of("$N.get()", fields.get(dependency));
-      collectDependenciesBuilder.addStatement(
-          "$T $L = $L",
-          futureType,
-          dependencyFutureName(dependency),
-          dependency.kind().equals(RequestKind.PRODUCED)
-              ? CodeBlock.of("$T.createFutureProduced($L)", PRODUCERS, futureAccess)
-              : futureAccess);
-    }
-    FutureTransform futureTransform = createFutureTransform(fields, binding, asyncDependencies);
-
-    collectDependenciesBuilder
-        .returns(listenableFutureOf(futureTransform.applyArgType()))
-        .addStatement("return $L", futureTransform.futureCodeBlock());
-
-    MethodSpec.Builder callProducesMethod =
-        methodBuilder("callProducesMethod")
-            .returns(futureTypeName)
-            .addAnnotation(Override.class)
-            .addModifiers(PUBLIC)
-            .addParameter(futureTransform.applyArgType(), futureTransform.applyArgName())
-            .addExceptions(binding.thrownTypes().stream().map(XType::getTypeName).collect(toList()))
-            .addCode(
-                getInvocationCodeBlock(
-                    binding, providedTypeName, futureTransform.parameterCodeBlocks()));
-    if (futureTransform.hasUncheckedCast()) {
-      callProducesMethod.addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED));
-    }
-
-    MethodSpec constructor = constructorBuilder.build();
-    factoryBuilder
-        .superclass(
-            ParameterizedTypeName.get(
-                TypeNames.ABSTRACT_PRODUCES_METHOD_PRODUCER,
-                futureTransform.applyArgType(),
-                providedTypeName))
-        .addMethod(constructor)
-        .addMethod(staticFactoryMethod(binding, constructor))
-        .addMethod(collectDependenciesBuilder.build())
-        .addMethod(callProducesMethod.build());
+            .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+            .addFields(
+                factoryFields.getAll().stream()
+                    // The executor and monitor fields are owned by the superclass so they are not
+                    // included as fields in the generated factory subclass.
+                    .filter(field -> !field.equals(factoryFields.executorField))
+                    .filter(field -> !field.equals(factoryFields.monitorField))
+                    .collect(toImmutableList()))
+            .addMethod(constructorMethod(binding, factoryFields))
+            .addMethods(staticCreateMethod(binding, factoryFields))
+            .addMethod(collectDependenciesMethod(binding, factoryFields))
+            .addMethod(callProducesMethod(binding, factoryFields));
 
     gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
 
-    // TODO(gak): write a sensible toString
     return ImmutableList.of(factoryBuilder);
   }
 
-  private MethodSpec staticFactoryMethod(ProductionBinding binding, MethodSpec constructor) {
+  // private FooModule_ProducesFooFactory(
+  //     FooModule module,
+  //     Provider<Executor> executorProvider,
+  //     Provider<ProductionComponentMonitor> productionComponentMonitorProvider,
+  //     Producer<Foo> fooProducer,
+  //     Producer<Bar> barProducer) {
+  //   super(
+  //       productionComponentMonitorProvider,
+  //       ProducerToken.create(FooModule_ProducesFooFactory.class),
+  //       executorProvider);
+  //   this.module = module;
+  //   this.fooProducer = Producers.nonCancellationPropagatingViewOf(fooProducer);
+  //   this.barProducer = Producers.nonCancellationPropagatingViewOf(barProducer);
+  // }
+  private MethodSpec constructorMethod(ProductionBinding binding, FactoryFields factoryFields) {
+    MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PRIVATE);
+    constructorBuilder.addStatement(
+        "super($N, $L, $N)",
+        factoryFields.monitorField,
+        producerTokenConstruction(toJavaPoet(generatedClassNameForBinding(binding)), binding),
+        factoryFields.executorField);
+    factoryFields.getAll()
+        .forEach(
+            field -> {
+              constructorBuilder.addParameter(field.type, field.name);
+              // The executor and monitor fields belong to the super class so they don't need a
+              // field assignment here.
+              if (!field.equals(factoryFields.executorField)
+                      && !field.equals(factoryFields.monitorField)) {
+                if (TypeNames.rawTypeName(field.type).equals(TypeNames.PRODUCER)) {
+                  constructorBuilder.addStatement(
+                      "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)",
+                      field,
+                      TypeNames.PRODUCERS);
+                } else {
+                  constructorBuilder.addStatement("this.$1N = $1N", field);
+                }
+              }
+            });
+    return constructorBuilder.build();
+  }
+
+  // public static FooModule_ProducesFooFactory create(
+  //     FooModule module,
+  //     Provider<Executor> executorProvider,
+  //     Provider<ProductionComponentMonitor> productionComponentMonitorProvider,
+  //     Producer<Foo> fooProducer,
+  //     Producer<Bar> barProducer) {
+  //   return new FooModule_ProducesFooFactory(
+  //       module, executorProvider, productionComponentMonitorProvider, fooProducer, barProducer);
+  // }
+  private ImmutableList<MethodSpec> staticCreateMethod(
+      ProductionBinding binding, FactoryFields factoryFields) {
+    ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
+    List<ParameterSpec> params = constructorMethod(binding, factoryFields).parameters;
+    methodsBuilder.add(MethodSpec.methodBuilder("create")
+        .addModifiers(PUBLIC, STATIC)
+        .returns(parameterizedGeneratedTypeNameForBinding(binding))
+        .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+        .addParameters(params)
+        .addStatement(
+            "return new $T($L)",
+            parameterizedGeneratedTypeNameForBinding(binding),
+            parameterNames(params))
+        .build());
+    // If any of the parameters take a Dagger Provider type, we also need to make a
+    // Javax Provider type for backwards compatibility with components generated at
+    // an older version.
+    // Eventually, we will need to remove this and break backwards compatibility
+    // in order to fully cut the Javax dependency.
+    if (hasDaggerProviderParams(params)) {
+      methodsBuilder.add(javaxCreateMethod(binding, params));
+    }
+    return methodsBuilder.build();
+  }
+
+  private MethodSpec javaxCreateMethod(ProductionBinding binding, List<ParameterSpec> params) {
+    ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(params);
     return MethodSpec.methodBuilder("create")
         .addModifiers(PUBLIC, STATIC)
         .returns(parameterizedGeneratedTypeNameForBinding(binding))
         .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
-        .addParameters(constructor.parameters)
+        .addParameters(remappedParams)
         .addStatement(
             "return new $T($L)",
             parameterizedGeneratedTypeNameForBinding(binding),
-            constructor.parameters.stream()
-                .map(p -> CodeBlock.of("$N", p.name))
-                .collect(toParametersCodeBlock()))
+            wrappedParametersCodeBlock(remappedParams))
         .build();
   }
 
-  // TODO(ronshapiro): consolidate versions of these
-  private static FieldSpec addFieldAndConstructorParameter(
-      TypeSpec.Builder typeBuilder,
-      MethodSpec.Builder constructorBuilder,
-      String variableName,
-      TypeName variableType) {
-    FieldSpec field = FieldSpec.builder(variableType, variableName, PRIVATE, FINAL).build();
-    typeBuilder.addField(field);
-    constructorBuilder.addParameter(field.type, field.name);
-    return field;
-  }
-
-  private static CodeBlock fieldAssignment(FieldSpec field, FrameworkField frameworkField) {
-    CodeBlock.Builder statement = CodeBlock.builder();
-    if (frameworkField.type() != null
-        && TypeNames.rawTypeName(frameworkField.type()).equals(TypeNames.PRODUCER)) {
-      statement.addStatement(
-          "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)", field, TypeNames.PRODUCERS);
-    } else {
-      statement.addStatement("this.$1N = $1N", field);
-    }
-    return statement.build();
-  }
-
-  private static void assignField(
-      MethodSpec.Builder constructorBuilder, FieldSpec field, ParameterizedTypeName type) {
-    if (type != null && type.rawType.equals(TypeNames.PRODUCER)) {
-      constructorBuilder.addStatement(
-          "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)", field, TypeNames.PRODUCERS);
-    } else {
-      constructorBuilder.addStatement("this.$1N = $1N", field);
+  // Example 1: No async dependencies.
+  // protected ListenableFuture<Void> collectDependencies() {
+  //   return Futures.<Void>immediateFuture(null);
+  // }
+  //
+  // Example 2: Single async dependency, "fooProducer".
+  // protected ListenableFuture<Foo> collectDependencies() {
+  //   return fooProducer.get();
+  // }
+  //
+  // Example 3: Multiple async dependencies, "fooProducer" and "barProducer".
+  // protected ListenableFuture<List<Object>> collectDependencies() {
+  //   ListenableFuture<Foo> fooFuture = fooProducer.get();
+  //   ListenableFuture<Bar> barFuture = barProducer.get();
+  //   return Futures.<Object>allAsList(fooFuture, barFuture);
+  // }
+  public MethodSpec collectDependenciesMethod(
+      ProductionBinding binding, FactoryFields factoryFields) {
+    MethodSpec.Builder methodBuilder =
+        methodBuilder("collectDependencies")
+            .addAnnotation(Override.class)
+            .addModifiers(PROTECTED);
+    ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
+    switch (asyncDependencies.size()) {
+      case 0:
+        return methodBuilder
+            .returns(listenableFutureOf(VOID_CLASS))
+            .addStatement("return $T.<$T>immediateFuture(null)", FUTURES, VOID_CLASS)
+            .build();
+      case 1: {
+        DependencyRequest asyncDependency = getOnlyElement(asyncDependencies);
+        FieldSpec asyncDependencyField = factoryFields.get(asyncDependency);
+        return methodBuilder
+            .returns(listenableFutureOf(asyncDependencyType(asyncDependency)))
+            .addStatement("return $L", producedCodeBlock(asyncDependency, asyncDependencyField))
+            .build();
+      }
+      default:
+        CodeBlock.Builder argAssignments = CodeBlock.builder();
+        ImmutableList.Builder<CodeBlock> argNames = ImmutableList.builder();
+        for (DependencyRequest asyncDependency : asyncDependencies) {
+          FieldSpec asyncDependencyField = factoryFields.get(asyncDependency);
+          argNames.add(CodeBlock.of("$L", dependencyFutureName(asyncDependency)));
+          argAssignments.addStatement(
+              "$T $L = $L",
+              listenableFutureOf(asyncDependencyType(asyncDependency)),
+              dependencyFutureName(asyncDependency),
+              producedCodeBlock(asyncDependency, asyncDependencyField));
+        }
+        return methodBuilder
+            .returns(listenableFutureOf(listOf(OBJECT)))
+            .addCode(argAssignments.build())
+            .addStatement(
+                "return $T.<$T>allAsList($L)",
+                FUTURES,
+                OBJECT,
+                makeParametersCodeBlock(argNames.build()))
+            .build();
     }
   }
 
-  /** Returns a list of dependencies that are generated asynchronously. */
-  private static ImmutableList<DependencyRequest> asyncDependencies(Binding binding) {
+  private CodeBlock producedCodeBlock(DependencyRequest request, FieldSpec field) {
+    return request.kind() == RequestKind.PRODUCED
+        ? CodeBlock.of("$T.createFutureProduced($N.get())", PRODUCERS, field)
+        : CodeBlock.of("$N.get()", field);
+  }
+
+  // Example 1: No async dependencies.
+  // @Override
+  // public ListenableFuture<Foo> callProducesMethod(Void ignoredVoidArg) {
+  //   return module.producesFoo();
+  // }
+  //
+  // Example 2: Single async dependency.
+  // @Override
+  // public ListenableFuture<Foo> callProducesMethod(Bar bar) {
+  //   return module.producesFoo(bar);
+  // }
+  //
+  // Example 3: Multiple async dependencies.
+  // @Override
+  // @SuppressWarnings("unchecked")
+  // public ListenableFuture<Foo> callProducesMethod(List<Object> args) {
+  //   return module.producesFoo((Bar) args.get(0), (Baz) args.get(1));
+  // }
+  private MethodSpec callProducesMethod(ProductionBinding binding, FactoryFields factoryFields) {
+    TypeName contributedTypeName = binding.contributedType().getTypeName();
+    ParameterSpec parameter = callProducesMethodParameter(binding);
+    MethodSpec.Builder methodBuilder =
+        methodBuilder("callProducesMethod")
+            .returns(listenableFutureOf(contributedTypeName))
+            .addAnnotation(Override.class)
+            .addModifiers(PUBLIC)
+            .addExceptions(
+                asMethod(binding.bindingElement().get()).getThrownTypes().stream()
+                    .map(XType::getTypeName)
+                    .collect(toImmutableList()))
+            .addParameter(parameter);
+    ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
+    ImmutableList.Builder<CodeBlock> parameterCodeBlocks = ImmutableList.builder();
+    for (DependencyRequest dependency : binding.explicitDependencies()) {
+      if (isAsyncDependency(dependency)) {
+        if (asyncDependencies.size() > 1) {
+          TypeName dependencyType = asyncDependencyType(dependency);
+          int argIndex = asyncDependencies.indexOf(dependency);
+          parameterCodeBlocks.add(
+              CodeBlock.of("($T) $N.get($L)", dependencyType, parameter, argIndex));
+        } else {
+          parameterCodeBlocks.add(CodeBlock.of("$N", parameter));
+        }
+      } else {
+        parameterCodeBlocks.add(
+            sourceFiles.frameworkTypeUsageStatement(
+                CodeBlock.of("$N", factoryFields.get(dependency)), dependency.kind()));
+      }
+    }
+    if (asyncDependencies.size() > 1) {
+      methodBuilder.addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED));
+    }
+
+    CodeBlock moduleCodeBlock =
+        CodeBlock.of(
+            "$L.$L($L)",
+            factoryFields.moduleField.isPresent()
+                ? factoryFields.moduleField.get().name
+                : CodeBlock.of("$T", binding.bindingTypeElement().get().getClassName()),
+            getSimpleName(binding.bindingElement().get()),
+            makeParametersCodeBlock(parameterCodeBlocks.build()));
+
+    switch (ProductionKind.fromProducesMethod(asMethod(binding.bindingElement().get()))) {
+      case IMMEDIATE:
+        methodBuilder.addStatement(
+            "return $T.<$T>immediateFuture($L)", FUTURES, contributedTypeName, moduleCodeBlock);
+        break;
+      case FUTURE:
+        methodBuilder.addStatement("return $L", moduleCodeBlock);
+        break;
+      case SET_OF_FUTURE:
+        methodBuilder.addStatement("return $T.allAsSet($L)", PRODUCERS, moduleCodeBlock);
+        break;
+    }
+    return methodBuilder.build();
+  }
+
+  private ParameterSpec callProducesMethodParameter(ProductionBinding binding) {
+    ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
+    switch (asyncDependencies.size()) {
+      case 0:
+        return ParameterSpec.builder(VOID_CLASS, "ignoredVoidArg").build();
+      case 1:
+        DependencyRequest asyncDependency = getOnlyElement(asyncDependencies);
+        String argName = getSimpleName(asyncDependency.requestElement().get().xprocessing());
+        return ParameterSpec.builder(
+                asyncDependencyType(asyncDependency),
+                argName.equals("module") ? "moduleArg" : argName)
+            .build();
+      default:
+        return ParameterSpec.builder(listOf(OBJECT), "args").build();
+    }
+  }
+
+  private static ImmutableList<DependencyRequest> asyncDependencies(ProductionBinding binding) {
     return binding.dependencies().stream()
         .filter(ProducerFactoryGenerator::isAsyncDependency)
         .collect(toImmutableList());
@@ -305,184 +415,6 @@
     return getSimpleName(dependency.requestElement().get().xprocessing()) + "Future";
   }
 
-  private FutureTransform createFutureTransform(
-        ImmutableMap<DependencyRequest, FieldSpec> fields,
-        ProductionBinding binding,
-        ImmutableList<DependencyRequest> asyncDependencies) {
-      if (asyncDependencies.isEmpty()) {
-        return new NoArgFutureTransform(fields, binding);
-      } else if (asyncDependencies.size() == 1) {
-        return new SingleArgFutureTransform(
-            fields, binding, Iterables.getOnlyElement(asyncDependencies));
-      } else {
-        return new MultiArgFutureTransform(fields, binding, asyncDependencies);
-      }
-    }
-
-  /** Represents the transformation of an input future by a producer method. */
-  abstract class FutureTransform {
-    protected final ImmutableMap<DependencyRequest, FieldSpec> fields;
-    protected final ProductionBinding binding;
-
-    FutureTransform(ImmutableMap<DependencyRequest, FieldSpec> fields, ProductionBinding binding) {
-      this.fields = fields;
-      this.binding = binding;
-    }
-
-    /** The code block representing the future that should be transformed. */
-    abstract CodeBlock futureCodeBlock();
-
-    /** The type of the argument to the apply method. */
-    abstract TypeName applyArgType();
-
-    /** The name of the argument to the apply method */
-    abstract String applyArgName();
-
-    /** The code blocks to be passed to the produces method itself. */
-    abstract ImmutableList<CodeBlock> parameterCodeBlocks();
-
-    /** Whether the transform method has an unchecked cast. */
-    boolean hasUncheckedCast() {
-      return false;
-    }
-
-    CodeBlock frameworkTypeUsageStatement(DependencyRequest dependency) {
-      return sourceFiles.frameworkTypeUsageStatement(
-          CodeBlock.of("$N", fields.get(dependency)), dependency.kind());
-    }
-  }
-
-  final class NoArgFutureTransform extends FutureTransform {
-    NoArgFutureTransform(
-        ImmutableMap<DependencyRequest, FieldSpec> fields, ProductionBinding binding) {
-      super(fields, binding);
-    }
-
-    @Override
-    CodeBlock futureCodeBlock() {
-      return CodeBlock.of("$T.<$T>immediateFuture(null)", FUTURES, VOID_CLASS);
-    }
-
-    @Override
-    TypeName applyArgType() {
-      return VOID_CLASS;
-    }
-
-    @Override
-    String applyArgName() {
-      return "ignoredVoidArg";
-    }
-
-    @Override
-    ImmutableList<CodeBlock> parameterCodeBlocks() {
-      return binding.explicitDependencies().stream()
-          .map(this::frameworkTypeUsageStatement)
-          .collect(toImmutableList());
-    }
-  }
-
-  final class SingleArgFutureTransform extends FutureTransform {
-    private final DependencyRequest asyncDependency;
-
-    SingleArgFutureTransform(
-        ImmutableMap<DependencyRequest, FieldSpec> fields,
-        ProductionBinding binding,
-        DependencyRequest asyncDependency) {
-      super(fields, binding);
-      this.asyncDependency = asyncDependency;
-    }
-
-    @Override
-    CodeBlock futureCodeBlock() {
-      return CodeBlock.of("$L", dependencyFutureName(asyncDependency));
-    }
-
-    @Override
-    TypeName applyArgType() {
-      return asyncDependencyType(asyncDependency);
-    }
-
-    @Override
-    String applyArgName() {
-      String argName = getSimpleName(asyncDependency.requestElement().get().xprocessing());
-      if (argName.equals("module")) {
-        return "moduleArg";
-      }
-      return argName;
-    }
-
-    @Override
-    ImmutableList<CodeBlock> parameterCodeBlocks() {
-      ImmutableList.Builder<CodeBlock> parameterCodeBlocks = ImmutableList.builder();
-      for (DependencyRequest dependency : binding.explicitDependencies()) {
-        // We really want to compare instances here, because asyncDependency is an element in the
-        // set binding.dependencies().
-        if (dependency == asyncDependency) {
-          parameterCodeBlocks.add(CodeBlock.of("$L", applyArgName()));
-        } else {
-          parameterCodeBlocks.add(frameworkTypeUsageStatement(dependency));
-        }
-      }
-      return parameterCodeBlocks.build();
-    }
-  }
-
-  final class MultiArgFutureTransform extends FutureTransform {
-    private final ImmutableList<DependencyRequest> asyncDependencies;
-
-    MultiArgFutureTransform(
-        ImmutableMap<DependencyRequest, FieldSpec> fields,
-        ProductionBinding binding,
-        ImmutableList<DependencyRequest> asyncDependencies) {
-      super(fields, binding);
-      this.asyncDependencies = asyncDependencies;
-    }
-
-    @Override
-    CodeBlock futureCodeBlock() {
-      return CodeBlock.of(
-          "$T.<$T>allAsList($L)",
-          FUTURES,
-          OBJECT,
-          asyncDependencies
-              .stream()
-              .map(ProducerFactoryGenerator::dependencyFutureName)
-              .collect(joining(", ")));
-    }
-
-    @Override
-    TypeName applyArgType() {
-      return listOf(OBJECT);
-    }
-
-    @Override
-    String applyArgName() {
-      return "args";
-    }
-
-    @Override
-    ImmutableList<CodeBlock> parameterCodeBlocks() {
-      int argIndex = 0;
-      ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
-      for (DependencyRequest dependency : binding.explicitDependencies()) {
-        if (isAsyncDependency(dependency)) {
-          codeBlocks.add(
-              CodeBlock.of(
-                  "($T) $L.get($L)", asyncDependencyType(dependency), applyArgName(), argIndex));
-          argIndex++;
-        } else {
-          codeBlocks.add(frameworkTypeUsageStatement(dependency));
-        }
-      }
-      return codeBlocks.build();
-    }
-
-    @Override
-    boolean hasUncheckedCast() {
-      return true;
-    }
-  }
-
   private static boolean isAsyncDependency(DependencyRequest dependency) {
     switch (dependency.kind()) {
       case INSTANCE:
@@ -505,43 +437,60 @@
     }
   }
 
-  /**
-   * Creates a code block for the invocation of the producer method from the module, which should be
-   * used entirely within a method body.
-   *
-   * @param binding The binding to generate the invocation code block for.
-   * @param providedTypeName The type name that should be provided by this producer.
-   * @param parameterCodeBlocks The code blocks for all the parameters to the producer method.
-   */
-  private CodeBlock getInvocationCodeBlock(
-      ProductionBinding binding,
-      TypeName providedTypeName,
-      ImmutableList<CodeBlock> parameterCodeBlocks) {
-    CodeBlock moduleCodeBlock =
-        CodeBlock.of(
-            "$L.$L($L)",
-            binding.requiresModuleInstance()
-                ? "module"
-                : CodeBlock.of("$T", binding.bindingTypeElement().get().getClassName()),
-            getSimpleName(binding.bindingElement().get()),
-            makeParametersCodeBlock(parameterCodeBlocks));
+  /** Represents the available fields in the generated factory class. */
+  private static final class FactoryFields {
+    static FactoryFields create(ProductionBinding binding) {
+      UniqueNameSet nameSet = new UniqueNameSet();
+      // TODO(bcorso, dpb): Add a test for the case when a Factory parameter is named "module".
+      Optional<FieldSpec> moduleField =
+          binding.requiresModuleInstance()
+              ? Optional.of(
+                  createField(
+                      binding.bindingTypeElement().get().getType().getTypeName(),
+                      nameSet.getUniqueName("module")))
+              : Optional.empty();
 
-    final CodeBlock returnCodeBlock;
-    switch (binding.productionKind().get()) {
-      case IMMEDIATE:
-        returnCodeBlock =
-            CodeBlock.of("$T.<$T>immediateFuture($L)", FUTURES, providedTypeName, moduleCodeBlock);
-        break;
-      case FUTURE:
-        returnCodeBlock = moduleCodeBlock;
-        break;
-      case SET_OF_FUTURE:
-        returnCodeBlock = CodeBlock.of("$T.allAsSet($L)", PRODUCERS, moduleCodeBlock);
-        break;
-      default:
-        throw new AssertionError();
+      ImmutableMap.Builder<DependencyRequest, FieldSpec> builder =
+          ImmutableMap.builder();
+      generateBindingFieldsForDependencies(binding).forEach(
+          (dependency, field) ->
+              builder.put(
+                  dependency,
+                  createField(toJavaPoet(field.type()), nameSet.getUniqueName(field.name()))));
+      return new FactoryFields(binding, moduleField, builder.buildOrThrow());
     }
-    return CodeBlock.of("return $L;", returnCodeBlock);
+
+    private static FieldSpec createField(TypeName type, String name) {
+      return FieldSpec.builder(type, name, PRIVATE, FINAL).build();
+    }
+
+    private final Optional<FieldSpec> moduleField;
+    private final FieldSpec monitorField;
+    private final FieldSpec executorField;
+    private final ImmutableMap<DependencyRequest, FieldSpec> frameworkFields;
+
+    private FactoryFields(
+        ProductionBinding binding,
+        Optional<FieldSpec> moduleField,
+        ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
+      this.moduleField = moduleField;
+      this.monitorField = frameworkFields.get(binding.monitorRequest());
+      this.executorField = frameworkFields.get(binding.executorRequest());
+      this.frameworkFields = frameworkFields;
+    }
+
+    FieldSpec get(DependencyRequest request) {
+      return frameworkFields.get(request);
+    }
+
+    ImmutableList<FieldSpec> getAll() {
+      return moduleField.isPresent()
+          ? ImmutableList.<FieldSpec>builder()
+              .add(moduleField.get())
+              .addAll(frameworkFields.values())
+              .build()
+          : frameworkFields.values().asList();
+    }
   }
 
   @Override
@@ -549,4 +498,27 @@
     // TODO(beder): examine if we can remove this or prevent subtypes of Future from being produced
     return ImmutableSet.of(FUTURE_RETURN_VALUE_IGNORED);
   }
+
+  /** What kind of object a {@code @Produces}-annotated method returns. */
+  private enum ProductionKind {
+    /** A value. */
+    IMMEDIATE,
+    /** A {@code ListenableFuture<T>}. */
+    FUTURE,
+    /** A {@code Set<ListenableFuture<T>>}. */
+    SET_OF_FUTURE;
+
+    /** Returns the kind of object a {@code @Produces}-annotated method returns. */
+    static ProductionKind fromProducesMethod(XMethodElement producesMethod) {
+      if (isFutureType(producesMethod.getReturnType())) {
+        return FUTURE;
+      } else if (ContributionType.fromBindingElement(producesMethod)
+              .equals(ContributionType.SET_VALUES)
+          && isFutureType(SetType.from(producesMethod.getReturnType()).elementType())) {
+        return SET_OF_FUTURE;
+      } else {
+        return IMMEDIATE;
+      }
+    }
+  }
 }
diff --git a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
index 9d08956..2b54779 100644
--- a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
@@ -17,15 +17,16 @@
 package dagger.internal.codegen.writing;
 
 
+import androidx.room.compiler.codegen.XClassName;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.xprocessing.XTypeNames;
 import java.util.Optional;
 
 /** An {@code Producer} creation expression for provision bindings. */
@@ -49,8 +50,8 @@
   }
 
   @Override
-  public Optional<ClassName> alternativeFrameworkClass() {
-    return Optional.of(TypeNames.PRODUCER);
+  public Optional<XClassName> alternativeFrameworkClass() {
+    return Optional.of(XTypeNames.PRODUCER);
   }
 
   @AssistedFactory
diff --git a/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
index 0793d6e..b646641 100644
--- a/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
@@ -24,8 +24,11 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.ProductionBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
+import dagger.internal.codegen.model.RequestKind;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
@@ -35,15 +38,15 @@
  * that binding.
  */
 final class ProductionBindingRepresentation implements BindingRepresentation {
-  private final ProductionBinding binding;
+  private final ContributionBinding binding;
   private final DerivedFromFrameworkInstanceRequestRepresentation.Factory
       derivedFromFrameworkInstanceRequestRepresentationFactory;
-  private final RequestRepresentation frameworkInstanceRequestRepresentation;
+  private final RequestRepresentation producerNodeInstanceRequestRepresentation;
   private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
 
   @AssistedInject
   ProductionBindingRepresentation(
-      @Assisted ProductionBinding binding,
+      @Assisted ContributionBinding binding,
       ComponentImplementation componentImplementation,
       DerivedFromFrameworkInstanceRequestRepresentation.Factory
           derivedFromFrameworkInstanceRequestRepresentationFactory,
@@ -66,7 +69,7 @@
                     ? bindingRepresentations.scope(
                         binding, unscopedFrameworkInstanceCreationExpressionFactory.create(binding))
                     : unscopedFrameworkInstanceCreationExpressionFactory.create(binding));
-    this.frameworkInstanceRequestRepresentation =
+    this.producerNodeInstanceRequestRepresentation =
         producerNodeInstanceRequestRepresentationFactory.create(binding, frameworkInstanceSupplier);
   }
 
@@ -77,11 +80,11 @@
   }
 
   private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
-    return request.frameworkType().isPresent()
-        ? frameworkInstanceRequestRepresentation
+    return request.requestKind().equals(RequestKind.PRODUCER)
+        ? producerNodeInstanceRequestRepresentation
         : derivedFromFrameworkInstanceRequestRepresentationFactory.create(
             binding,
-            frameworkInstanceRequestRepresentation,
+            producerNodeInstanceRequestRepresentation,
             request.requestKind(),
             FrameworkType.PRODUCER_NODE);
   }
@@ -93,10 +96,10 @@
   private Optional<MemberSelect> staticFactoryCreation() {
     if (binding.dependencies().isEmpty()) {
       if (binding.kind().equals(MULTIBOUND_MAP)) {
-        return Optional.of(StaticMemberSelects.emptyMapFactory(binding));
+        return Optional.of(StaticMemberSelects.emptyMapFactory((MultiboundMapBinding) binding));
       }
       if (binding.kind().equals(MULTIBOUND_SET)) {
-        return Optional.of(StaticMemberSelects.emptySetFactory(binding));
+        return Optional.of(StaticMemberSelects.emptySetFactory((MultiboundSetBinding) binding));
       }
     }
     return Optional.empty();
@@ -104,6 +107,6 @@
 
   @AssistedFactory
   static interface Factory {
-    ProductionBindingRepresentation create(ProductionBinding binding);
+    ProductionBindingRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java
index f031a72..cfdc718 100644
--- a/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProviderInstanceRequestRepresentation.java
@@ -20,15 +20,15 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.ProvisionBinding;
 
 /** Binding expression for provider instances. */
 final class ProviderInstanceRequestRepresentation extends FrameworkInstanceRequestRepresentation {
 
   @AssistedInject
   ProviderInstanceRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       SwitchingProviderInstanceSupplier.Factory switchingProviderInstanceSupplierFactory,
       StaticFactoryInstanceSupplier.Factory staticFactoryInstanceSupplierFactory,
       ProviderInstanceSupplier.Factory providerInstanceSupplierFactory,
@@ -51,7 +51,7 @@
   }
 
   private static FrameworkInstanceSupplier frameworkInstanceSupplier(
-      ProvisionBinding binding,
+      ContributionBinding binding,
       SwitchingProviderInstanceSupplier.Factory switchingProviderInstanceSupplierFactory,
       StaticFactoryInstanceSupplier.Factory staticFactoryInstanceSupplierFactory,
       ProviderInstanceSupplier.Factory providerInstanceSupplierFactory,
@@ -71,6 +71,6 @@
 
   @AssistedFactory
   static interface Factory {
-    ProviderInstanceRequestRepresentation create(ProvisionBinding binding);
+    ProviderInstanceRequestRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java b/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java
index bbfb50c..b5ec6f9 100644
--- a/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java
+++ b/java/dagger/internal/codegen/writing/ProviderInstanceSupplier.java
@@ -19,7 +19,7 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 
 /** An object that initializes a framework-type component field for a binding. */
@@ -28,7 +28,7 @@
 
   @AssistedInject
   ProviderInstanceSupplier(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       ComponentImplementation componentImplementation,
       UnscopedFrameworkInstanceCreationExpressionFactory
           unscopedFrameworkInstanceCreationExpressionFactory,
@@ -51,6 +51,6 @@
 
   @AssistedFactory
   static interface Factory {
-    ProviderInstanceSupplier create(ProvisionBinding binding);
+    ProviderInstanceSupplier create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
index 0f9b6f3..35cdb0d 100644
--- a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
@@ -24,7 +24,8 @@
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
 import dagger.internal.codegen.model.RequestKind;
 import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
 
@@ -35,13 +36,13 @@
 final class ProvisionBindingRepresentation implements BindingRepresentation {
   private final BindingGraph graph;
   private final CompilerMode compilerMode;
-  private final ProvisionBinding binding;
+  private final ContributionBinding binding;
   private final DirectInstanceBindingRepresentation directInstanceBindingRepresentation;
   private final FrameworkInstanceBindingRepresentation frameworkInstanceBindingRepresentation;
 
   @AssistedInject
   ProvisionBindingRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       DirectInstanceBindingRepresentation.Factory directInstanceBindingRepresentationFactory,
       FrameworkInstanceBindingRepresentation.Factory frameworkInstanceBindingRepresentationFactory,
       BindingGraph graph,
@@ -72,7 +73,7 @@
     // be handled with simple pre-check in the graph. For example, a provider for a subcomponent
     // builder is backed with its direct instance, returning framework instance for both cases will
     // form a loop. There are also difficulties introduced by manually created framework requests.
-    // TODO(wanyingd): refactor framework instance so that we don't need to generate both direct
+    // TODO(bcorso): refactor framework instance so that we don't need to generate both direct
     // instance and framework instance representation for the same binding.
     if (compilerMode.isFastInit() && graph.topLevelBindingGraph().hasFrameworkRequest(binding)) {
       return false;
@@ -105,18 +106,18 @@
    * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
    * bindings whose scope is no stronger than their delegate's.
    */
-  static boolean needsCaching(ProvisionBinding binding, BindingGraph graph) {
+  static boolean needsCaching(ContributionBinding binding, BindingGraph graph) {
     if (!binding.scope().isPresent()) {
       return false;
     }
     if (binding.kind().equals(DELEGATE)) {
-      return isBindsScopeStrongerThanDependencyScope(binding, graph);
+      return isBindsScopeStrongerThanDependencyScope((DelegateBinding) binding, graph);
     }
     return true;
   }
 
   @AssistedFactory
   static interface Factory {
-    ProvisionBindingRepresentation create(ProvisionBinding binding);
+    ProvisionBindingRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
index 559bb7d..25b9fe1 100644
--- a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
 
@@ -27,18 +28,18 @@
 import dagger.internal.codegen.base.SetType;
 import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
 import dagger.internal.codegen.javapoet.TypeNames;
 import dagger.internal.codegen.model.DependencyRequest;
 
 /** A factory creation expression for a multibound set. */
 final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpression {
   private final BindingGraph graph;
-  private final ContributionBinding binding;
+  private final MultiboundSetBinding binding;
 
   @AssistedInject
   SetFactoryCreationExpression(
-      @Assisted ContributionBinding binding,
+      @Assisted MultiboundSetBinding binding,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations,
       BindingGraph graph) {
@@ -49,7 +50,8 @@
 
   @Override
   public CodeBlock creationExpression() {
-    CodeBlock.Builder builder = CodeBlock.builder().add("$T.", setFactoryClassName(binding));
+    CodeBlock.Builder builder =
+        CodeBlock.builder().add("$T.", toJavaPoet(setFactoryClassName(binding)));
     if (!useRawType()) {
       SetType setType = SetType.from(binding.key());
       builder.add(
@@ -96,6 +98,6 @@
 
   @AssistedFactory
   static interface Factory {
-    SetFactoryCreationExpression create(ContributionBinding binding);
+    SetFactoryCreationExpression create(MultiboundSetBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/SetRequestRepresentation.java b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
index 68a340a..f8c9d08 100644
--- a/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
@@ -34,7 +34,7 @@
 import dagger.internal.codegen.base.ContributionType;
 import dagger.internal.codegen.base.SetType;
 import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
 import dagger.internal.codegen.javapoet.CodeBlocks;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.javapoet.TypeNames;
@@ -43,14 +43,14 @@
 
 /** A binding expression for multibound sets. */
 final class SetRequestRepresentation extends RequestRepresentation {
-  private final ProvisionBinding binding;
+  private final MultiboundSetBinding binding;
   private final BindingGraph graph;
   private final ComponentRequestRepresentations componentRequestRepresentations;
   private final XProcessingEnv processingEnv;
 
   @AssistedInject
   SetRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted MultiboundSetBinding binding,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
       ComponentRequestRepresentations componentRequestRepresentations,
@@ -146,7 +146,7 @@
     return (!isSingleValue(dependency)
             && !isTypeAccessibleFrom(
                 binding.key().type().xprocessing(), requestingClass.packageName())
-            // TODO(wanyingd): Replace instanceof checks with validation on the binding.
+            // TODO(bcorso): Replace instanceof checks with validation on the binding.
             && (bindingExpression instanceof DerivedFromFrameworkInstanceRequestRepresentation
                 || bindingExpression instanceof DelegateRequestRepresentation))
         ? CodeBlocks.cast(expression, TypeNames.COLLECTION)
@@ -189,6 +189,6 @@
 
   @AssistedFactory
   static interface Factory {
-    SetRequestRepresentation create(ProvisionBinding binding);
+    SetRequestRepresentation create(MultiboundSetBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
index 79613fd..c284a14 100644
--- a/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
@@ -21,25 +21,33 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
 import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
+import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod.requiresInjectionMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
 import static dagger.internal.codegen.xprocessing.XElements.asMethod;
 import static dagger.internal.codegen.xprocessing.XProcessingEnvs.isPreJava8SourceVersion;
 
 import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.TypeName;
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.binding.AssistedInjectionBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.InjectionBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.model.DependencyRequest;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
@@ -50,9 +58,12 @@
  * {@link dagger.internal.codegen.model.RequestKind#INSTANCE} requests.
  */
 final class SimpleMethodRequestRepresentation extends RequestRepresentation {
+  private static final ImmutableSet<BindingKind> VALID_BINDING_KINDS =
+      ImmutableSet.of(BindingKind.INJECTION, BindingKind.ASSISTED_INJECTION, BindingKind.PROVISION);
+
   private final CompilerOptions compilerOptions;
   private final XProcessingEnv processingEnv;
-  private final ProvisionBinding provisionBinding;
+  private final ContributionBinding binding;
   private final ComponentRequestRepresentations componentRequestRepresentations;
   private final MembersInjectionMethods membersInjectionMethods;
   private final ComponentRequirementExpressions componentRequirementExpressions;
@@ -60,7 +71,7 @@
 
   @AssistedInject
   SimpleMethodRequestRepresentation(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       MembersInjectionMethods membersInjectionMethods,
       CompilerOptions compilerOptions,
       XProcessingEnv processingEnv,
@@ -69,11 +80,9 @@
       ComponentImplementation componentImplementation) {
     this.compilerOptions = compilerOptions;
     this.processingEnv = processingEnv;
-    this.provisionBinding = binding;
-    checkArgument(
-        provisionBinding.implicitDependencies().isEmpty(),
-        "framework deps are not currently supported");
-    checkArgument(provisionBinding.bindingElement().isPresent());
+    this.binding = binding;
+    checkArgument(VALID_BINDING_KINDS.contains(binding.kind()));
+    checkArgument(binding.bindingElement().isPresent());
     this.componentRequestRepresentations = componentRequestRepresentations;
     this.membersInjectionMethods = membersInjectionMethods;
     this.componentRequirementExpressions = componentRequirementExpressions;
@@ -82,7 +91,7 @@
 
   @Override
   Expression getDependencyExpression(ClassName requestingClass) {
-    return requiresInjectionMethod(provisionBinding, compilerOptions, requestingClass)
+    return requiresInjectionMethod(requestingClass)
         ? invokeInjectionMethod(requestingClass)
         : invokeMethod(requestingClass);
   }
@@ -92,11 +101,11 @@
     CodeBlock arguments =
         makeParametersCodeBlock(
             ProvisionMethod.invokeArguments(
-                provisionBinding,
+                binding,
                 request -> dependencyArgument(request, requestingClass).codeBlock(),
                 shardImplementation::getUniqueFieldNameForAssistedParam));
-    XElement bindingElement = provisionBinding.bindingElement().get();
-    XTypeElement bindingTypeElement = provisionBinding.bindingTypeElement().get();
+    XElement bindingElement = binding.bindingElement().get();
+    XTypeElement bindingTypeElement = binding.bindingTypeElement().get();
     CodeBlock invocation;
     if (isConstructor(bindingElement)) {
       invocation = CodeBlock.of("new $T($L)", constructorTypeName(requestingClass), arguments);
@@ -122,7 +131,7 @@
   }
 
   private TypeName constructorTypeName(ClassName requestingClass) {
-    XType type = provisionBinding.key().type().xprocessing();
+    XType type = binding.key().type().xprocessing();
     return type.getTypeArguments().stream()
             .allMatch(t -> isTypeAccessibleFrom(t, requestingClass.packageName()))
         ? type.getTypeName()
@@ -132,7 +141,7 @@
   private Expression invokeInjectionMethod(ClassName requestingClass) {
     return injectMembers(
         ProvisionMethod.invoke(
-            provisionBinding,
+            binding,
             request -> dependencyArgument(request, requestingClass).codeBlock(),
             shardImplementation::getUniqueFieldNameForAssistedParam,
             requestingClass,
@@ -147,25 +156,24 @@
   }
 
   private Expression injectMembers(CodeBlock instance, ClassName requestingClass) {
-    if (provisionBinding.injectionSites().isEmpty()) {
+    if (!hasInjectionSites(binding)) {
       return Expression.create(simpleMethodReturnType(), instance);
     }
     if (isPreJava8SourceVersion(processingEnv)) {
       // Java 7 type inference can't figure out that instance in
       // injectParameterized(Parameterized_Factory.newParameterized()) is Parameterized<T> and not
       // Parameterized<Object>
-      if (!provisionBinding.key().type().xprocessing().getTypeArguments().isEmpty()) {
-        TypeName keyType = provisionBinding.key().type().xprocessing().getTypeName();
+      if (!binding.key().type().xprocessing().getTypeArguments().isEmpty()) {
+        TypeName keyType = binding.key().type().xprocessing().getTypeName();
         instance = CodeBlock.of("($T) ($T) $L", keyType, rawTypeName(keyType), instance);
       }
     }
-    return membersInjectionMethods.getInjectExpression(
-        provisionBinding.key(), instance, requestingClass);
+    return membersInjectionMethods.getInjectExpression(binding.key(), instance, requestingClass);
   }
 
   private Optional<CodeBlock> moduleReference(ClassName requestingClass) {
-    return provisionBinding.requiresModuleInstance()
-        ? provisionBinding
+    return binding.requiresModuleInstance()
+        ? binding
             .contributingModule()
             .map(XTypeElement::getType)
             .map(ComponentRequirement::forModule)
@@ -174,13 +182,35 @@
   }
 
   private XType simpleMethodReturnType() {
-    return provisionBinding
-        .contributedPrimitiveType()
-        .orElse(provisionBinding.key().type().xprocessing());
+    return binding.contributedPrimitiveType().orElse(binding.key().type().xprocessing());
+  }
+
+  private boolean requiresInjectionMethod(ClassName requestingClass) {
+    XExecutableElement executableElement = asExecutable(binding.bindingElement().get());
+    return hasInjectionSites(binding)
+        || binding.shouldCheckForNull(compilerOptions)
+        || !isElementAccessibleFrom(executableElement, requestingClass.packageName())
+        // This check should be removable once we drop support for -source 7
+        || executableElement.getParameters().stream()
+            .map(XExecutableParameterElement::getType)
+            .anyMatch(type -> !isRawTypeAccessible(type, requestingClass.packageName()));
+  }
+
+  private static boolean hasInjectionSites(ContributionBinding binding) {
+    switch (binding.kind()) {
+      case INJECTION:
+        return !((InjectionBinding) binding).injectionSites().isEmpty();
+      case ASSISTED_INJECTION:
+        return !((AssistedInjectionBinding) binding).injectionSites().isEmpty();
+      case PROVISION:
+        return false;
+      default:
+        throw new AssertionError("Unexpected binding kind: " + binding.kind());
+    }
   }
 
   @AssistedFactory
   static interface Factory {
-    SimpleMethodRequestRepresentation create(ProvisionBinding binding);
+    SimpleMethodRequestRepresentation create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
index 070cd63..cab6352 100644
--- a/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
+++ b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
@@ -23,6 +23,8 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
 
 /** An object that returns static factory to satisfy framework instance request. */
 final class StaticFactoryInstanceSupplier implements FrameworkInstanceSupplier {
@@ -41,15 +43,15 @@
     return frameworkInstanceSupplier.memberSelect();
   }
 
-  // TODO(wanyingd): no-op members injector is currently handled in
+  // TODO(bcorso): no-op members injector is currently handled in
   // `MembersInjectorProviderCreationExpression`, we should inline the logic here so we won't create
   // an extra field for it.
   private MemberSelect staticFactoryCreation(ContributionBinding binding) {
     switch (binding.kind()) {
       case MULTIBOUND_MAP:
-        return StaticMemberSelects.emptyMapFactory(binding);
+        return StaticMemberSelects.emptyMapFactory((MultiboundMapBinding) binding);
       case MULTIBOUND_SET:
-        return StaticMemberSelects.emptySetFactory(binding);
+        return StaticMemberSelects.emptySetFactory((MultiboundSetBinding) binding);
       case PROVISION:
       case INJECTION:
         return StaticMemberSelects.factoryCreateNoArgumentMethod(binding);
diff --git a/java/dagger/internal/codegen/writing/StaticMemberSelects.java b/java/dagger/internal/codegen/writing/StaticMemberSelects.java
index a1ea63c..7b72316 100644
--- a/java/dagger/internal/codegen/writing/StaticMemberSelects.java
+++ b/java/dagger/internal/codegen/writing/StaticMemberSelects.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen.writing;
 
+import static androidx.room.compiler.codegen.compat.XConverters.toJavaPoet;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
@@ -38,13 +39,14 @@
 import dagger.internal.codegen.base.SetType;
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
 import dagger.internal.codegen.javapoet.CodeBlocks;
 
 /** Helper class for static member select creation. */
 final class StaticMemberSelects {
   /** A {@link MemberSelect} for a factory of an empty map. */
-  static MemberSelect emptyMapFactory(Binding binding) {
+  static MemberSelect emptyMapFactory(MultiboundMapBinding binding) {
     BindingType bindingType = binding.bindingType();
     ImmutableList<XType> typeParameters =
         ImmutableList.copyOf(binding.key().type().xprocessing().getTypeArguments());
@@ -60,9 +62,9 @@
    * dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
    * {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
    */
-  static MemberSelect emptySetFactory(ContributionBinding binding) {
+  static MemberSelect emptySetFactory(MultiboundSetBinding binding) {
     return new ParameterizedStaticMethod(
-        setFactoryClassName(binding),
+        toJavaPoet(setFactoryClassName(binding)),
         ImmutableList.of(SetType.from(binding.key()).elementType()),
         CodeBlock.of("empty()"),
         FACTORY);
@@ -82,7 +84,7 @@
         "%s should have no dependencies and be unscoped to create a no argument factory.",
         binding);
 
-    ClassName factoryName = generatedClassNameForBinding(binding);
+    ClassName factoryName = toJavaPoet(generatedClassNameForBinding(binding));
     XType keyType = binding.key().type().xprocessing();
     if (isDeclared(keyType)) {
       ImmutableList<TypeVariableName> typeVariables = bindingTypeElementTypeVariableNames(binding);
diff --git a/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java b/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java
index c71c70a..bc6b189 100644
--- a/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/SubcomponentCreatorRequestRepresentation.java
@@ -23,18 +23,19 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.binding.SubcomponentCreatorBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 
 /** A binding expression for a subcomponent creator that just invokes the constructor. */
 final class SubcomponentCreatorRequestRepresentation extends RequestRepresentation {
   private final ShardImplementation shardImplementation;
-  private final ContributionBinding binding;
+  private final SubcomponentCreatorBinding binding;
 
   @AssistedInject
   SubcomponentCreatorRequestRepresentation(
-      @Assisted ContributionBinding binding, ComponentImplementation componentImplementation) {
+      @Assisted SubcomponentCreatorBinding binding,
+      ComponentImplementation componentImplementation) {
     this.binding = binding;
     this.shardImplementation = componentImplementation.shardImplementation(binding);
   }
@@ -58,6 +59,6 @@
 
   @AssistedFactory
   static interface Factory {
-    SubcomponentCreatorRequestRepresentation create(ContributionBinding binding);
+    SubcomponentCreatorRequestRepresentation create(SubcomponentCreatorBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
index 6f8ca7b..4d944bd 100644
--- a/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
+++ b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
@@ -25,7 +25,7 @@
 import dagger.assisted.AssistedInject;
 import dagger.internal.codegen.binding.Binding;
 import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.ContributionBinding;
 import dagger.internal.codegen.model.BindingKind;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
@@ -39,7 +39,7 @@
 
   @AssistedInject
   SwitchingProviderInstanceSupplier(
-      @Assisted ProvisionBinding binding,
+      @Assisted ContributionBinding binding,
       BindingGraph graph,
       ComponentImplementation componentImplementation,
       UnscopedDirectInstanceRequestRepresentationFactory
@@ -80,6 +80,6 @@
 
   @AssistedFactory
   static interface Factory {
-    SwitchingProviderInstanceSupplier create(ProvisionBinding binding);
+    SwitchingProviderInstanceSupplier create(ContributionBinding binding);
   }
 }
diff --git a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
index cf4f260..88dd1c3 100644
--- a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
@@ -16,9 +16,17 @@
 
 package dagger.internal.codegen.writing;
 
-import dagger.internal.codegen.binding.ComponentRequirement;
+import dagger.internal.codegen.binding.AssistedFactoryBinding;
+import dagger.internal.codegen.binding.BoundInstanceBinding;
+import dagger.internal.codegen.binding.ComponentBinding;
+import dagger.internal.codegen.binding.ComponentDependencyBinding;
+import dagger.internal.codegen.binding.ComponentDependencyProvisionBinding;
 import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
+import dagger.internal.codegen.binding.OptionalBinding;
+import dagger.internal.codegen.binding.SubcomponentCreatorBinding;
 import dagger.internal.codegen.model.RequestKind;
 import javax.inject.Inject;
 
@@ -50,7 +58,6 @@
 
   @Inject
   UnscopedDirectInstanceRequestRepresentationFactory(
-      ComponentImplementation componentImplementation,
       AssistedFactoryRequestRepresentation.Factory assistedFactoryRequestRepresentationFactory,
       ComponentInstanceRequestRepresentation.Factory componentInstanceRequestRepresentationFactory,
       ComponentProvisionRequestRepresentation.Factory
@@ -84,40 +91,43 @@
   RequestRepresentation create(ContributionBinding binding) {
     switch (binding.kind()) {
       case DELEGATE:
-        return delegateRequestRepresentationFactory.create(binding, RequestKind.INSTANCE);
+        return delegateRequestRepresentationFactory.create(
+            (DelegateBinding) binding, RequestKind.INSTANCE);
 
       case COMPONENT:
-        return componentInstanceRequestRepresentationFactory.create(binding);
+        return componentInstanceRequestRepresentationFactory.create((ComponentBinding) binding);
 
       case COMPONENT_DEPENDENCY:
         return componentRequirementRequestRepresentationFactory.create(
-            binding, ComponentRequirement.forDependency(binding.key().type().xprocessing()));
+            (ComponentDependencyBinding) binding);
 
       case COMPONENT_PROVISION:
-        return componentProvisionRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return componentProvisionRequestRepresentationFactory.create(
+            (ComponentDependencyProvisionBinding) binding);
 
       case SUBCOMPONENT_CREATOR:
-        return subcomponentCreatorRequestRepresentationFactory.create(binding);
+        return subcomponentCreatorRequestRepresentationFactory.create(
+            (SubcomponentCreatorBinding) binding);
 
       case MULTIBOUND_SET:
-        return setRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return setRequestRepresentationFactory.create((MultiboundSetBinding) binding);
 
       case MULTIBOUND_MAP:
-        return mapRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return mapRequestRepresentationFactory.create((MultiboundMapBinding) binding);
 
       case OPTIONAL:
-        return optionalRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return optionalRequestRepresentationFactory.create((OptionalBinding) binding);
 
       case BOUND_INSTANCE:
         return componentRequirementRequestRepresentationFactory.create(
-            binding, ComponentRequirement.forBoundInstance(binding));
+            (BoundInstanceBinding) binding);
 
       case ASSISTED_FACTORY:
-        return assistedFactoryRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return assistedFactoryRequestRepresentationFactory.create((AssistedFactoryBinding) binding);
 
       case INJECTION:
       case PROVISION:
-        return simpleMethodRequestRepresentationFactory.create((ProvisionBinding) binding);
+        return simpleMethodRequestRepresentationFactory.create(binding);
 
       case ASSISTED_INJECTION:
       case MEMBERS_INJECTOR:
diff --git a/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
index 36807c2..c105cff 100644
--- a/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
@@ -17,9 +17,18 @@
 package dagger.internal.codegen.writing;
 
 import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.binding.BoundInstanceBinding;
+import dagger.internal.codegen.binding.ComponentDependencyBinding;
+import dagger.internal.codegen.binding.ComponentDependencyProductionBinding;
+import dagger.internal.codegen.binding.ComponentDependencyProvisionBinding;
 import dagger.internal.codegen.binding.ComponentRequirement;
 import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.binding.DelegateBinding;
+import dagger.internal.codegen.binding.MembersInjectorBinding;
+import dagger.internal.codegen.binding.MultiboundMapBinding;
+import dagger.internal.codegen.binding.MultiboundSetBinding;
+import dagger.internal.codegen.binding.OptionalBinding;
+import dagger.internal.codegen.binding.ProductionBinding;
 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
 import javax.inject.Inject;
 
@@ -109,14 +118,17 @@
 
       case BOUND_INSTANCE:
         return instanceFactoryCreationExpression(
-            binding, ComponentRequirement.forBoundInstance(binding));
+            binding,
+            ComponentRequirement.forBoundInstance((BoundInstanceBinding) binding));
 
       case COMPONENT_DEPENDENCY:
         return instanceFactoryCreationExpression(
-            binding, ComponentRequirement.forDependency(binding.key().type().xprocessing()));
+            binding,
+            ComponentRequirement.forDependency((ComponentDependencyBinding) binding));
 
       case COMPONENT_PROVISION:
-        return dependencyMethodProviderCreationExpressionFactory.create((ProvisionBinding) binding);
+        return dependencyMethodProviderCreationExpressionFactory.create(
+            (ComponentDependencyProvisionBinding) binding);
 
       case SUBCOMPONENT_CREATOR:
         return anonymousProviderCreationExpressionFactory.create(binding);
@@ -128,25 +140,28 @@
         return injectionOrProvisionProviderCreationExpressionFactory.create(binding);
 
       case COMPONENT_PRODUCTION:
-        return dependencyMethodProducerCreationExpressionFactory.create(binding);
+        return dependencyMethodProducerCreationExpressionFactory.create(
+            (ComponentDependencyProductionBinding) binding);
 
       case PRODUCTION:
-        return producerCreationExpressionFactory.create(binding);
+        return producerCreationExpressionFactory.create((ProductionBinding) binding);
 
       case MULTIBOUND_SET:
-        return setFactoryCreationExpressionFactory.create(binding);
+        return setFactoryCreationExpressionFactory.create((MultiboundSetBinding) binding);
 
       case MULTIBOUND_MAP:
-        return mapFactoryCreationExpressionFactory.create(binding);
+        return mapFactoryCreationExpressionFactory.create((MultiboundMapBinding) binding);
 
       case DELEGATE:
-        return delegatingFrameworkInstanceCreationExpressionFactory.create(binding);
+        return delegatingFrameworkInstanceCreationExpressionFactory.create(
+            (DelegateBinding) binding);
 
       case OPTIONAL:
-        return optionalFactoryInstanceCreationExpressionFactory.create(binding);
+        return optionalFactoryInstanceCreationExpressionFactory.create((OptionalBinding) binding);
 
       case MEMBERS_INJECTOR:
-        return membersInjectorProviderCreationExpressionFactory.create((ProvisionBinding) binding);
+        return membersInjectorProviderCreationExpressionFactory.create(
+            (MembersInjectorBinding) binding);
 
       default:
         throw new AssertionError(binding);
diff --git a/java/dagger/internal/codegen/xprocessing/BUILD b/java/dagger/internal/codegen/xprocessing/BUILD
index da465e1..f03b2f9 100644
--- a/java/dagger/internal/codegen/xprocessing/BUILD
+++ b/java/dagger/internal/codegen/xprocessing/BUILD
@@ -15,7 +15,7 @@
 # Description:
 #   Import for including XProcessing in Dagger.
 
-load("@rules_java//java:defs.bzl", "java_import")
+load("@rules_java//java:defs.bzl", "java_import", "java_library")
 
 package(default_visibility = ["//:src"])
 
@@ -32,6 +32,7 @@
         "//java/dagger/internal/codegen/extension",
         "//java/dagger/spi",
         "//third_party/java/auto:common",
+        "//third_party/java/auto:value",
         "//third_party/java/guava/base",
         "//third_party/java/guava/collect",
         "//third_party/java/javapoet",
@@ -63,6 +64,8 @@
     exports = [
         ":xprocessing-testing-lib",
         "@maven//:com_google_devtools_ksp_symbol_processing",
+        "@maven//:com_google_devtools_ksp_symbol_processing_aa_embeddable",
+        "@maven//:com_google_devtools_ksp_symbol_processing_common_deps",
         "@maven//:org_jetbrains_kotlin_kotlin_annotation_processing_embeddable",
         "@maven//:org_jetbrains_kotlin_kotlin_compiler_embeddable",
         "@maven//:org_jetbrains_kotlin_kotlin_daemon_embeddable",
diff --git a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
index bf8e94f..26246ff 100644
--- a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
+++ b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
@@ -16,11 +16,14 @@
 
 package dagger.internal.codegen.xprocessing;
 
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
 
 import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XType;
 import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeSpec;
 
@@ -53,5 +56,23 @@
     return ParameterSpec.builder(param.getType().getTypeName(), param.getJvmName()).build();
   }
 
+  public static ParameterSpec toParameterSpec(
+      XExecutableParameterElement parameter, XType parameterType) {
+    Nullability nullability = Nullability.of(parameter);
+    ImmutableSet<AnnotationSpec> typeUseNullableAnnotations =
+        nullability.typeUseNullableAnnotations().stream()
+            .map(annotation -> AnnotationSpec.builder(annotation).build())
+            .collect(toImmutableSet());
+    ImmutableSet<AnnotationSpec> nonTypeUseNullableAnnotations =
+        nullability.nonTypeUseNullableAnnotations().stream()
+            .map(annotation -> AnnotationSpec.builder(annotation).build())
+            .collect(toImmutableSet());
+    return ParameterSpec.builder(
+            parameterType.getTypeName().annotated(typeUseNullableAnnotations.asList()),
+            parameter.getJvmName())
+        .addAnnotations(nonTypeUseNullableAnnotations)
+        .build();
+  }
+
   private JavaPoetExt() {}
 }
diff --git a/java/dagger/internal/codegen/xprocessing/MethodSpecs.java b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java
index cc8c2f4..2eaac12 100644
--- a/java/dagger/internal/codegen/xprocessing/MethodSpecs.java
+++ b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java
@@ -16,15 +16,17 @@
 
 package dagger.internal.codegen.xprocessing;
 
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.JavaPoetExt.toParameterSpec;
 import static javax.lang.model.element.Modifier.PROTECTED;
 import static javax.lang.model.element.Modifier.PUBLIC;
 
+import androidx.room.compiler.processing.XExecutableParameterElement;
 import androidx.room.compiler.processing.XMethodElement;
 import androidx.room.compiler.processing.XMethodType;
 import androidx.room.compiler.processing.XType;
+import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
 
 // TODO(bcorso): Consider moving these methods into XProcessing library.
 /** A utility class for {@link MethodSpec} helper methods. */
@@ -33,22 +35,36 @@
   /** Returns a {@link MethodSpec} that overrides the given method. */
   public static MethodSpec.Builder overriding(XMethodElement method, XType owner) {
     XMethodType methodType = method.asMemberOf(owner);
+    Nullability nullability = Nullability.of(method);
     MethodSpec.Builder builder =
         // We're overriding the method so we have to use the jvm name here.
         MethodSpec.methodBuilder(method.getJvmName())
             .addAnnotation(Override.class)
+            .addAnnotations(
+                nullability.nonTypeUseNullableAnnotations().stream()
+                    .map(AnnotationSpec::builder)
+                    .map(AnnotationSpec.Builder::build)
+                    .collect(toImmutableList()))
             .addTypeVariables(methodType.getTypeVariableNames())
             .varargs(method.isVarArgs())
-            .returns(methodType.getReturnType().getTypeName());
+            .returns(
+                methodType
+                    .getReturnType()
+                    .getTypeName()
+                    .annotated(
+                        nullability.typeUseNullableAnnotations().stream()
+                            .map(AnnotationSpec::builder)
+                            .map(AnnotationSpec.Builder::build)
+                            .collect(toImmutableList())));
     if (method.isPublic()) {
       builder.addModifiers(PUBLIC);
     } else if (method.isProtected()) {
       builder.addModifiers(PROTECTED);
     }
     for (int i = 0; i < methodType.getParameterTypes().size(); i++) {
-      String parameterName = method.getParameters().get(i).getJvmName();
-      TypeName parameterType = methodType.getParameterTypes().get(i).getTypeName();
-      builder.addParameter(ParameterSpec.builder(parameterType, parameterName).build());
+      XExecutableParameterElement parameter = method.getParameters().get(i);
+      XType parameterType = methodType.getParameterTypes().get(i);
+      builder.addParameter(toParameterSpec(parameter, parameterType));
     }
     method.getThrownTypes().stream().map(XType::getTypeName).forEach(builder::addException);
     return builder;
diff --git a/java/dagger/internal/codegen/xprocessing/Nullability.java b/java/dagger/internal/codegen/xprocessing/Nullability.java
new file mode 100644
index 0000000..e704858
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/Nullability.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.xprocessing;
+
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isVariableElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asVariable;
+
+import androidx.room.compiler.processing.XAnnotated;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XNullability;
+import androidx.room.compiler.processing.XType;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import java.util.Optional;
+
+/**
+ * Contains information about the nullability of an element or type.
+ *
+ * <p>Note that an element can be nullable if either:
+ *
+ * <ul>
+ *   <li>The element is annotated with {@code Nullable} or
+ *   <li>the associated kotlin type is nullable (i.e. {@code T?} types in Kotlin source).
+ * </ul>
+ */
+@AutoValue
+public abstract class Nullability {
+  /** A constant that can represent any non-null element. */
+  public static final Nullability NOT_NULLABLE =
+      new AutoValue_Nullability(ImmutableSet.of(), ImmutableSet.of(), false);
+
+  public static Nullability of(XElement element) {
+    ImmutableSet<ClassName> nonTypeUseNullableAnnotations = getNullableAnnotations(element);
+    Optional<XType> type = getType(element);
+    ImmutableSet<ClassName> typeUseNullableAnnotations =
+    ImmutableSet.of();
+    boolean isKotlinTypeNullable =
+        // Note: Technically, it isn't possible for Java sources to have nullable types like in
+        // Kotlin sources, but for some reason KSP treats certain types as nullable if they have a
+        // specific @Nullable (TYPE_USE target) annotation. Thus, to avoid inconsistencies with
+        // KAPT, just ignore type nullability for elements in java sources.
+        !element.getClosestMemberContainer().isFromJava()
+            && type.isPresent()
+            && type.get().getNullability() == XNullability.NULLABLE;
+    return new AutoValue_Nullability(
+        nonTypeUseNullableAnnotations,
+        // Filter type use annotations that are also found on the element as non-type use
+        // annotations. This prevents them from being applied twice in some scenarios and just
+        // defaults to using them in the way before Dagger supported type use annotations.
+        Sets.difference(typeUseNullableAnnotations, nonTypeUseNullableAnnotations).immutableCopy(),
+        isKotlinTypeNullable);
+  }
+
+  private static ImmutableSet<ClassName> getNullableAnnotations(XAnnotated annotated) {
+    return annotated.getAllAnnotations().stream()
+        .map(XAnnotations::getClassName)
+        .filter(annotation -> annotation.simpleName().contentEquals("Nullable"))
+        .collect(toImmutableSet());
+  }
+
+  private static Optional<XType> getType(XElement element) {
+    if (isMethod(element)) {
+      return Optional.of(asMethod(element).getReturnType());
+    } else if (isVariableElement(element)) {
+      return Optional.of(asVariable(element).getType());
+    }
+    return Optional.empty();
+  }
+
+  public abstract ImmutableSet<ClassName> nonTypeUseNullableAnnotations();
+
+  public abstract ImmutableSet<ClassName> typeUseNullableAnnotations();
+
+  /**
+   * Returns {@code true} if the element's type is a Kotlin nullable type, e.g. {@code Foo?}.
+   *
+   * <p>Note that this method ignores any {@code @Nullable} type annotations and only looks for
+   * explicit {@code ?} usages on kotlin types.
+   */
+  public abstract boolean isKotlinTypeNullable();
+
+  public ImmutableSet<ClassName> nullableAnnotations() {
+    return ImmutableSet.<ClassName>builder()
+        .addAll(nonTypeUseNullableAnnotations())
+        .addAll(typeUseNullableAnnotations()).build();
+  }
+
+  public final boolean isNullable() {
+    return isKotlinTypeNullable() || !nullableAnnotations().isEmpty();
+  }
+
+  Nullability() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XElements.java b/java/dagger/internal/codegen/xprocessing/XElements.java
index b63d4d9..2f7efce 100644
--- a/java/dagger/internal/codegen/xprocessing/XElements.java
+++ b/java/dagger/internal/codegen/xprocessing/XElements.java
@@ -329,16 +329,22 @@
         return asTypeElement(element).getQualifiedName();
       } else if (isExecutable(element)) {
         XExecutableElement executable = asExecutable(element);
+        // TODO(b/318709946) resolving ksp types can be expensive, therefore we should avoid it
+        // here for extreme cases until ksp improved the performance.
+        boolean tooManyParameters =
+            getProcessingEnv(element).getBackend().equals(XProcessingEnv.Backend.KSP)
+                && executable.getParameters().size() > 10;
         return String.format(
             "%s(%s)",
             getSimpleName(
-                isConstructor(element)
-                    ? asConstructor(element).getEnclosingElement()
-                    : executable),
-            executable.getParameters().stream()
-                .map(XExecutableParameterElement::getType)
-                .map(XTypes::toStableString)
-                .collect(joining(",")));
+                isConstructor(element) ? asConstructor(element).getEnclosingElement() : executable),
+            (tooManyParameters
+                    ? executable.getParameters().stream().limit(10)
+                    : executable.getParameters().stream()
+                        .map(XExecutableParameterElement::getType)
+                        .map(XTypes::toStableString)
+                        .collect(joining(",")))
+                + (tooManyParameters ? ", ..." : ""));
       } else if (isEnumEntry(element)
                      || isField(element)
                      || isMethodParameter(element)
diff --git a/java/dagger/internal/codegen/xprocessing/XTypeElements.java b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
index 7330b8f..33b0f5b 100644
--- a/java/dagger/internal/codegen/xprocessing/XTypeElements.java
+++ b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
@@ -81,7 +81,7 @@
         .collect(toImmutableList());
   }
 
-  // TODO(wanyingd): rename this to getAllMethodsWithoutPrivate, since the private method declared
+  // TODO(bcorso): rename this to getAllMethodsWithoutPrivate, since the private method declared
   // within this element is being filtered out. This doesn't mirror {@code
   // MoreElements#getAllMethods}'s behavior but have the same name, and can cause confusion to
   // developers.
diff --git a/java/dagger/internal/codegen/xprocessing/XTypeNames.java b/java/dagger/internal/codegen/xprocessing/XTypeNames.java
new file mode 100644
index 0000000..d9c7213
--- /dev/null
+++ b/java/dagger/internal/codegen/xprocessing/XTypeNames.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen.xprocessing;
+
+import static com.google.common.collect.Iterables.getLast;
+
+import androidx.room.compiler.codegen.XClassName;
+import androidx.room.compiler.codegen.XTypeName;
+import androidx.room.compiler.processing.XType;
+import com.google.common.collect.ImmutableSet;
+
+/** Common names and convenience methods for XPoet {@link XTypeName} usage. */
+public final class XTypeNames {
+
+  // Dagger Core classnames
+  public static final XClassName ASSISTED = XClassName.Companion.get("dagger.assisted", "Assisted");
+  public static final XClassName ASSISTED_FACTORY =
+      XClassName.Companion.get("dagger.assisted", "AssistedFactory");
+  public static final XClassName ASSISTED_INJECT =
+      XClassName.Companion.get("dagger.assisted", "AssistedInject");
+  public static final XClassName BINDS = XClassName.Companion.get("dagger", "Binds");
+  public static final XClassName BINDS_INSTANCE =
+      XClassName.Companion.get("dagger", "BindsInstance");
+  public static final XClassName BINDS_OPTIONAL_OF =
+      XClassName.Companion.get("dagger", "BindsOptionalOf");
+  public static final XClassName COMPONENT = XClassName.Companion.get("dagger", "Component");
+  public static final XClassName COMPONENT_BUILDER =
+      XClassName.Companion.get("dagger", "Component", "Builder");
+  public static final XClassName COMPONENT_FACTORY =
+      XClassName.Companion.get("dagger", "Component", "Factory");
+  public static final XClassName DAGGER_PROCESSING_OPTIONS =
+      XClassName.Companion.get("dagger", "DaggerProcessingOptions");
+  public static final XClassName ELEMENTS_INTO_SET =
+      XClassName.Companion.get("dagger.multibindings", "ElementsIntoSet");
+  public static final XClassName INTO_MAP =
+      XClassName.Companion.get("dagger.multibindings", "IntoMap");
+  public static final XClassName INTO_SET =
+      XClassName.Companion.get("dagger.multibindings", "IntoSet");
+  public static final XClassName MAP_KEY = XClassName.Companion.get("dagger", "MapKey");
+  public static final XClassName MODULE = XClassName.Companion.get("dagger", "Module");
+  public static final XClassName MULTIBINDS =
+      XClassName.Companion.get("dagger.multibindings", "Multibinds");
+  public static final XClassName PROVIDES = XClassName.Companion.get("dagger", "Provides");
+  public static final XClassName REUSABLE = XClassName.Companion.get("dagger", "Reusable");
+  public static final XClassName SUBCOMPONENT = XClassName.Companion.get("dagger", "Subcomponent");
+  public static final XClassName SUBCOMPONENT_BUILDER =
+      XClassName.Companion.get("dagger", "Subcomponent", "Builder");
+  public static final XClassName SUBCOMPONENT_FACTORY =
+      XClassName.Companion.get("dagger", "Subcomponent", "Factory");
+
+  // Dagger Internal classnames
+  public static final XClassName IDENTIFIER_NAME_STRING =
+      XClassName.Companion.get("dagger.internal", "IdentifierNameString");
+  public static final XClassName KEEP_FIELD_TYPE =
+      XClassName.Companion.get("dagger.internal", "KeepFieldType");
+  public static final XClassName LAZY_CLASS_KEY =
+      XClassName.Companion.get("dagger.multibindings", "LazyClassKey");
+  public static final XClassName LAZY_CLASS_KEY_MAP =
+      XClassName.Companion.get("dagger.internal", "LazyClassKeyMap");
+  public static final XClassName LAZY_CLASS_KEY_MAP_FACTORY =
+      XClassName.Companion.get("dagger.internal", "LazyClassKeyMap", "MapFactory");
+  public static final XClassName LAZY_CLASS_KEY_MAP_PROVIDER_FACTORY =
+      XClassName.Companion.get("dagger.internal", "LazyClassKeyMap", "MapProviderFactory");
+  public static final XClassName LAZY_MAP_OF_PRODUCED_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "LazyMapOfProducedProducer");
+  public static final XClassName LAZY_MAP_OF_PRODUCER_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "LazyMapOfProducerProducer");
+  public static final XClassName LAZY_MAP_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "LazyMapProducer");
+
+  public static final XClassName DELEGATE_FACTORY =
+      XClassName.Companion.get("dagger.internal", "DelegateFactory");
+  public static final XClassName DOUBLE_CHECK =
+      XClassName.Companion.get("dagger.internal", "DoubleCheck");
+
+  public static final XClassName FACTORY = XClassName.Companion.get("dagger.internal", "Factory");
+  public static final XClassName INJECTED_FIELD_SIGNATURE =
+      XClassName.Companion.get("dagger.internal", "InjectedFieldSignature");
+  public static final XClassName INSTANCE_FACTORY =
+      XClassName.Companion.get("dagger.internal", "InstanceFactory");
+  public static final XClassName MAP_BUILDER =
+      XClassName.Companion.get("dagger.internal", "MapBuilder");
+  public static final XClassName MAP_FACTORY =
+      XClassName.Companion.get("dagger.internal", "MapFactory");
+  public static final XClassName MAP_PROVIDER_FACTORY =
+      XClassName.Companion.get("dagger.internal", "MapProviderFactory");
+  public static final XClassName MEMBERS_INJECTOR =
+      XClassName.Companion.get("dagger", "MembersInjector");
+  public static final XClassName MEMBERS_INJECTORS =
+      XClassName.Companion.get("dagger.internal", "MembersInjectors");
+  public static final XClassName PROVIDER = XClassName.Companion.get("javax.inject", "Provider");
+  public static final XClassName DAGGER_PROVIDER =
+      XClassName.Companion.get("dagger.internal", "Provider");
+  public static final XClassName DAGGER_PROVIDERS =
+      XClassName.Companion.get("dagger.internal", "Providers");
+  public static final XClassName PROVIDER_OF_LAZY =
+      XClassName.Companion.get("dagger.internal", "ProviderOfLazy");
+  public static final XClassName SCOPE_METADATA =
+      XClassName.Companion.get("dagger.internal", "ScopeMetadata");
+  public static final XClassName QUALIFIER_METADATA =
+      XClassName.Companion.get("dagger.internal", "QualifierMetadata");
+  public static final XClassName SET_FACTORY =
+      XClassName.Companion.get("dagger.internal", "SetFactory");
+  public static final XClassName SINGLE_CHECK =
+      XClassName.Companion.get("dagger.internal", "SingleCheck");
+  public static final XClassName LAZY = XClassName.Companion.get("dagger", "Lazy");
+
+  // Dagger Producers classnames
+  public static final XClassName ABSTRACT_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "AbstractProducer");
+  public static final XClassName ABSTRACT_PRODUCES_METHOD_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "AbstractProducesMethodProducer");
+  public static final XClassName CANCELLATION_LISTENER =
+      XClassName.Companion.get("dagger.producers.internal", "CancellationListener");
+  public static final XClassName CANCELLATION_POLICY =
+      XClassName.Companion.get("dagger.producers", "CancellationPolicy");
+  public static final XClassName DELEGATE_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "DelegateProducer");
+  public static final XClassName DEPENDENCY_METHOD_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "DependencyMethodProducer");
+  public static final XClassName MAP_OF_PRODUCED_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "MapOfProducedProducer");
+  public static final XClassName MAP_OF_PRODUCER_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "MapOfProducerProducer");
+  public static final XClassName MAP_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "MapProducer");
+  public static final XClassName MONITORS =
+      XClassName.Companion.get("dagger.producers.monitoring.internal", "Monitors");
+  public static final XClassName PRODUCED =
+      XClassName.Companion.get("dagger.producers", "Produced");
+  public static final XClassName PRODUCER =
+      XClassName.Companion.get("dagger.producers", "Producer");
+  public static final XClassName PRODUCERS =
+      XClassName.Companion.get("dagger.producers.internal", "Producers");
+  public static final XClassName PRODUCER_MODULE =
+      XClassName.Companion.get("dagger.producers", "ProducerModule");
+  public static final XClassName PRODUCES =
+      XClassName.Companion.get("dagger.producers", "Produces");
+  public static final XClassName PRODUCTION =
+      XClassName.Companion.get("dagger.producers", "Production");
+  public static final XClassName PRODUCTION_COMPONENT =
+      XClassName.Companion.get("dagger.producers", "ProductionComponent");
+  public static final XClassName PRODUCTION_COMPONENT_BUILDER =
+      XClassName.Companion.get("dagger.producers", "ProductionComponent", "Builder");
+  public static final XClassName PRODUCTION_COMPONENT_FACTORY =
+      XClassName.Companion.get("dagger.producers", "ProductionComponent", "Factory");
+  public static final XClassName PRODUCTION_EXECTUTOR_MODULE =
+      XClassName.Companion.get("dagger.producers.internal", "ProductionExecutorModule");
+  public static final XClassName PRODUCTION_IMPLEMENTATION =
+      XClassName.Companion.get("dagger.producers.internal", "ProductionImplementation");
+  public static final XClassName PRODUCTION_SUBCOMPONENT =
+      XClassName.Companion.get("dagger.producers", "ProductionSubcomponent");
+  public static final XClassName PRODUCTION_SUBCOMPONENT_BUILDER =
+      XClassName.Companion.get("dagger.producers", "ProductionSubcomponent", "Builder");
+  public static final XClassName PRODUCTION_SUBCOMPONENT_FACTORY =
+      XClassName.Companion.get("dagger.producers", "ProductionSubcomponent", "Factory");
+  public static final XClassName PRODUCER_TOKEN =
+      XClassName.Companion.get("dagger.producers.monitoring", "ProducerToken");
+  public static final XClassName PRODUCTION_COMPONENT_MONITOR =
+      XClassName.Companion.get("dagger.producers.monitoring", "ProductionComponentMonitor");
+  public static final XClassName PRODUCTION_COMPONENT_MONITOR_FACTORY =
+      XClassName.Companion.get(
+          "dagger.producers.monitoring", "ProductionComponentMonitor", "Factory");
+  public static final XClassName SET_OF_PRODUCED_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "SetOfProducedProducer");
+  public static final XClassName SET_PRODUCER =
+      XClassName.Companion.get("dagger.producers.internal", "SetProducer");
+  public static final XClassName PRODUCTION_SCOPE =
+      XClassName.Companion.get("dagger.producers", "ProductionScope");
+
+  // Other classnames
+  public static final XClassName EXECUTOR =
+      XClassName.Companion.get("java.util.concurrent", "Executor");
+  public static final XClassName ERROR = XClassName.Companion.get("java.lang", "Error");
+  public static final XClassName EXCEPTION = XClassName.Companion.get("java.lang", "Exception");
+  public static final XClassName RUNTIME_EXCEPTION =
+      XClassName.Companion.get("java.lang", "RuntimeException");
+  public static final XClassName STRING = XClassName.Companion.get("java.lang", "String");
+
+  public static final XClassName MAP = XClassName.Companion.get("java.util", "Map");
+  public static final XClassName KOTLIN_METADATA = XClassName.Companion.get("kotlin", "Metadata");
+  public static final XClassName IMMUTABLE_MAP =
+      XClassName.Companion.get("com.google.common.collect", "ImmutableMap");
+  public static final XClassName SINGLETON =
+      XClassName.Companion.get("jakarta.inject", "Singleton");
+  public static final XClassName SINGLETON_JAVAX =
+      XClassName.Companion.get("javax.inject", "Singleton");
+  public static final XClassName SCOPE = XClassName.Companion.get("jakarta.inject", "Scope");
+  public static final XClassName SCOPE_JAVAX = XClassName.Companion.get("javax.inject", "Scope");
+  public static final XClassName INJECT = XClassName.Companion.get("jakarta.inject", "Inject");
+  public static final XClassName INJECT_JAVAX = XClassName.Companion.get("javax.inject", "Inject");
+  public static final XClassName QUALIFIER =
+      XClassName.Companion.get("jakarta.inject", "Qualifier");
+  public static final XClassName QUALIFIER_JAVAX =
+      XClassName.Companion.get("javax.inject", "Qualifier");
+  public static final XClassName COLLECTION = XClassName.Companion.get("java.util", "Collection");
+  public static final XClassName LIST = XClassName.Companion.get("java.util", "List");
+  public static final XClassName SET = XClassName.Companion.get("java.util", "Set");
+  public static final XClassName IMMUTABLE_SET =
+      XClassName.Companion.get("com.google.common.collect", "ImmutableSet");
+  public static final XClassName FUTURES =
+      XClassName.Companion.get("com.google.common.util.concurrent", "Futures");
+  public static final XClassName LISTENABLE_FUTURE =
+      XClassName.Companion.get("com.google.common.util.concurrent", "ListenableFuture");
+  public static final XClassName FLUENT_FUTURE =
+      XClassName.Companion.get("com.google.common.util.concurrent", "FluentFuture");
+  public static final XClassName GUAVA_OPTIONAL =
+      XClassName.Companion.get("com.google.common.base", "Optional");
+  public static final XClassName JDK_OPTIONAL = XClassName.Companion.get("java.util", "Optional");
+  public static final XClassName OVERRIDE = XClassName.Companion.get("java.lang", "Override");
+  public static final XClassName JVM_STATIC = XClassName.Companion.get("kotlin.jvm", "JvmStatic");
+  public static final XClassName CLASS = XClassName.Companion.get("java.lang", "Class");
+  public static final XClassName KCLASS = XClassName.Companion.get("kotlin.reflect", "KClass");
+
+  public static XTypeName abstractProducerOf(XTypeName typeName) {
+    return ABSTRACT_PRODUCER.parametrizedBy(typeName);
+  }
+
+  public static XTypeName factoryOf(XTypeName factoryType) {
+    return FACTORY.parametrizedBy(factoryType);
+  }
+
+  public static XTypeName lazyOf(XTypeName typeName) {
+    return LAZY.parametrizedBy(typeName);
+  }
+
+  public static XTypeName listOf(XTypeName typeName) {
+    return LIST.parametrizedBy(typeName);
+  }
+
+  public static XTypeName listenableFutureOf(XTypeName typeName) {
+    return LISTENABLE_FUTURE.parametrizedBy(typeName);
+  }
+
+  public static XTypeName membersInjectorOf(XTypeName membersInjectorType) {
+    return MEMBERS_INJECTOR.parametrizedBy(membersInjectorType);
+  }
+
+  public static XTypeName producedOf(XTypeName typeName) {
+    return PRODUCED.parametrizedBy(typeName);
+  }
+
+  public static XTypeName producerOf(XTypeName typeName) {
+    return PRODUCER.parametrizedBy(typeName);
+  }
+
+  public static XTypeName dependencyMethodProducerOf(XTypeName typeName) {
+    return DEPENDENCY_METHOD_PRODUCER.parametrizedBy(typeName);
+  }
+
+  public static XTypeName providerOf(XTypeName typeName) {
+    return PROVIDER.parametrizedBy(typeName);
+  }
+
+  public static XTypeName daggerProviderOf(XTypeName typeName) {
+    return DAGGER_PROVIDER.parametrizedBy(typeName);
+  }
+
+  public static XTypeName setOf(XTypeName elementType) {
+    return SET.parametrizedBy(elementType);
+  }
+
+  private static final ImmutableSet<XClassName> FUTURE_TYPES =
+      ImmutableSet.of(LISTENABLE_FUTURE, FLUENT_FUTURE);
+
+  public static boolean isFutureType(XType type) {
+    return isFutureType(type.asTypeName());
+  }
+
+  public static boolean isFutureType(XTypeName typeName) {
+    return FUTURE_TYPES.contains(typeName.getRawTypeName());
+  }
+
+  public static String simpleName(XClassName className) {
+    return getLast(className.getSimpleNames());
+  }
+
+  private XTypeNames() {}
+}
diff --git a/java/dagger/internal/codegen/xprocessing/XTypes.java b/java/dagger/internal/codegen/xprocessing/XTypes.java
index 7f4b77a..62d9dba 100644
--- a/java/dagger/internal/codegen/xprocessing/XTypes.java
+++ b/java/dagger/internal/codegen/xprocessing/XTypes.java
@@ -250,7 +250,11 @@
       case JAVAC:
         return isDeclared(type)
             && type.getTypeArguments().isEmpty()
-            && !type.getTypeElement().getType().getTypeArguments().isEmpty();
+            // TODO(b/353979671): We previously called:
+            //     type.getTypeElement().getType().getTypeArguments().isEmpty()
+            // which is a bit more symmetric to the call above, but that resulted in b/353979671, so
+            // we've switched to checking `XTypeElement#getTypeParameters()` until the bug is fixed.
+            && !type.getTypeElement().getTypeParameters().isEmpty();
       case KSP:
         return isDeclared(type)
             // TODO(b/245619245): Due to the bug in XProcessing, the logic used for Javac won't work
diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar
index 4d0d7fd..f7f0203 100644
--- a/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar
+++ b/java/dagger/internal/codegen/xprocessing/xprocessing-testing.jar
Binary files differ
diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
index 24590f8..31833cc 100644
--- a/java/dagger/internal/codegen/xprocessing/xprocessing.jar
+++ b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
Binary files differ
diff --git a/java/dagger/internal/package-info.java b/java/dagger/internal/package-info.java
new file mode 100644
index 0000000..2d83541
--- /dev/null
+++ b/java/dagger/internal/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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.
+ */
+
+@NullMarked
+package dagger.internal;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/java/dagger/lint/BUILD b/java/dagger/lint/BUILD
index 173d035..1e11aa2 100644
--- a/java/dagger/lint/BUILD
+++ b/java/dagger/lint/BUILD
@@ -15,9 +15,9 @@
 # Description:
 #   Dagger Lint Rules
 
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 load("//:build_defs.bzl", "POM_VERSION")
-load("//tools:maven.bzl", "gen_maven_artifact")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/producers/BUILD b/java/dagger/producers/BUILD
index 0dfd4d9..5bc7a5b 100644
--- a/java/dagger/producers/BUILD
+++ b/java/dagger/producers/BUILD
@@ -23,7 +23,7 @@
     "JAVA_RELEASE_MIN",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
diff --git a/java/dagger/producers/internal/LazyMapOfProducedProducer.java b/java/dagger/producers/internal/LazyMapOfProducedProducer.java
new file mode 100644
index 0000000..edc3ddb
--- /dev/null
+++ b/java/dagger/producers/internal/LazyMapOfProducedProducer.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.producers.internal;
+
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.internal.LazyClassKeyMap;
+import dagger.producers.Produced;
+import java.util.Map;
+
+/**
+ * Wrapper around {@link MapOfProducedProducer} to be compatible with @LazyClassKey annotated map.
+ */
+public final class LazyMapOfProducedProducer<V>
+    extends AbstractProducer<Map<Class<?>, Produced<V>>> {
+  AbstractProducer<Map<String, Produced<V>>> delegate;
+
+  public static <V> LazyMapOfProducedProducer<V> of(
+      AbstractProducer<Map<String, Produced<V>>> delegate) {
+    return new LazyMapOfProducedProducer<V>(delegate);
+  }
+
+  private LazyMapOfProducedProducer(AbstractProducer<Map<String, Produced<V>>> delegate) {
+    this.delegate = delegate;
+  }
+
+  @Override
+  public ListenableFuture<Map<Class<?>, Produced<V>>> compute() {
+    return Futures.transform(
+        delegate.compute(),
+        new Function<Map<String, Produced<V>>, Map<Class<?>, Produced<V>>>() {
+          @Override
+          public Map<Class<?>, Produced<V>> apply(Map<String, Produced<V>> classMap) {
+            return LazyClassKeyMap.of(classMap);
+          }
+        },
+        directExecutor());
+  }
+}
diff --git a/java/dagger/producers/internal/LazyMapOfProducerProducer.java b/java/dagger/producers/internal/LazyMapOfProducerProducer.java
new file mode 100644
index 0000000..b792557
--- /dev/null
+++ b/java/dagger/producers/internal/LazyMapOfProducerProducer.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.producers.internal;
+
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.internal.LazyClassKeyMap;
+import dagger.producers.Producer;
+import java.util.Map;
+
+/**
+ * Wrapper around {@link MapOfProducerProducer} to be compatible with @LazyClassKey annotated map.
+ */
+public final class LazyMapOfProducerProducer<V>
+    extends AbstractProducer<Map<Class<?>, Producer<V>>> {
+  AbstractProducer<Map<String, Producer<V>>> delegate;
+
+  public static <V> LazyMapOfProducerProducer<V> of(
+      AbstractProducer<Map<String, Producer<V>>> delegate) {
+    return new LazyMapOfProducerProducer<V>(delegate);
+  }
+
+  private LazyMapOfProducerProducer(AbstractProducer<Map<String, Producer<V>>> delegate) {
+    this.delegate = delegate;
+  }
+
+  @Override
+  public ListenableFuture<Map<Class<?>, Producer<V>>> compute() {
+    return Futures.transform(
+        delegate.compute(),
+        new Function<Map<String, Producer<V>>, Map<Class<?>, Producer<V>>>() {
+          @Override
+          public Map<Class<?>, Producer<V>> apply(Map<String, Producer<V>> classMap) {
+            return LazyClassKeyMap.of((Map<String, Producer<V>>) classMap);
+          }
+        },
+        directExecutor());
+  }
+}
diff --git a/java/dagger/producers/internal/LazyMapProducer.java b/java/dagger/producers/internal/LazyMapProducer.java
new file mode 100644
index 0000000..a09795c
--- /dev/null
+++ b/java/dagger/producers/internal/LazyMapProducer.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.producers.internal;
+
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.internal.LazyClassKeyMap;
+import java.util.Map;
+
+/** Wrapper around {@link MapProducer} to be compatible with @LazyClassKey annotated map. */
+public final class LazyMapProducer<V> extends AbstractProducer<Map<Class<?>, V>> {
+  AbstractProducer<Map<String, V>> delegate;
+
+  public static <V> LazyMapProducer<V> of(AbstractProducer<Map<String, V>> delegate) {
+    return new LazyMapProducer<V>(delegate);
+  }
+
+  private LazyMapProducer(AbstractProducer<Map<String, V>> delegate) {
+    this.delegate = delegate;
+  }
+
+  @Override
+  public ListenableFuture<Map<Class<?>, V>> compute() {
+    return Futures.transform(
+        delegate.compute(),
+        new Function<Map<String, V>, Map<Class<?>, V>>() {
+          @Override
+          public Map<Class<?>, V> apply(Map<String, V> classMap) {
+            return LazyClassKeyMap.of((Map<String, V>) classMap);
+          }
+        },
+        directExecutor());
+  }
+}
diff --git a/java/dagger/proguard.pro b/java/dagger/proguard.pro
index 1bfc947..150194d 100644
--- a/java/dagger/proguard.pro
+++ b/java/dagger/proguard.pro
@@ -1,3 +1,3 @@
--keepclasseswithmembers,includedescriptorclasses class * {
+-keepclassmembers,includedescriptorclasses class * {
    @dagger.internal.KeepFieldType <fields>;
 }
\ No newline at end of file
diff --git a/java/dagger/r8.pro b/java/dagger/r8.pro
index 17e0ffe..6fde1b2 100644
--- a/java/dagger/r8.pro
+++ b/java/dagger/r8.pro
@@ -1,3 +1,3 @@
 -identifiernamestring @dagger.internal.IdentifierNameString class ** {
     static java.lang.String *;
-}
\ No newline at end of file
+}
diff --git a/java/dagger/spi/BUILD b/java/dagger/spi/BUILD
index 8084e63..9624019 100644
--- a/java/dagger/spi/BUILD
+++ b/java/dagger/spi/BUILD
@@ -22,7 +22,7 @@
     "DOCLINT_REFERENCES",
     "POM_VERSION",
 )
-load("//tools:maven.bzl", "gen_maven_artifact")
+load("//tools/maven:maven.bzl", "gen_maven_artifact")
 
 package(default_visibility = ["//:src"])
 
@@ -80,7 +80,7 @@
     # util/deploy-dagger.sh
     shaded_deps = [
         "//third_party/java/auto:common",
-        "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
+        "//third_party/kotlin/kotlin_metadata_jvm",
         "//java/dagger/internal/codegen/xprocessing:xprocessing-jar",
     ],
 )
diff --git a/java/dagger/spi/model/BUILD b/java/dagger/spi/model/BUILD
index e5af4e5..9567c82 100644
--- a/java/dagger/spi/model/BUILD
+++ b/java/dagger/spi/model/BUILD
@@ -15,7 +15,7 @@
 # Description:
 #   Dagger's core APIs exposed for plugins
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 
 package(default_visibility = [
     # The dagger/spi should be the only direct dependent on this target.
@@ -36,7 +36,7 @@
 kt_jvm_library(
     name = "model",
     srcs = [":model-srcs"],
-    # TODO(wanyingd): Add javacopts explicitly once kt_jvm_library supports them.
+    # TODO(bcorso): Add javacopts explicitly once kt_jvm_library supports them.
     deps = [
         "//java/dagger:core",
         "//java/dagger/internal/codegen/extension",
diff --git a/java/dagger/spi/model/BindingGraphPlugin.java b/java/dagger/spi/model/BindingGraphPlugin.java
index 8edb702..007cd5a 100644
--- a/java/dagger/spi/model/BindingGraphPlugin.java
+++ b/java/dagger/spi/model/BindingGraphPlugin.java
@@ -60,6 +60,14 @@
   }
 
   /**
+   * Runs before each round of Dagger annotation processing.
+   *
+   * <p>If using the plugin to process elements that need resetting at the beginning of each
+   * processing round, use this function to perform the setup.
+   */
+  default void onProcessingRoundBegin() {}
+
+  /**
    * Perform any extra work after the plugin finished all its visiting. This will be called once per
    * instance of this plugin, after all graphs were {@linkplain #visitGraph(BindingGraph,
    * DiagnosticReporter) visited}
diff --git a/java/dagger/spi/model/DaggerExecutableElement.java b/java/dagger/spi/model/DaggerExecutableElement.java
index afbd8e0..c585505 100644
--- a/java/dagger/spi/model/DaggerExecutableElement.java
+++ b/java/dagger/spi/model/DaggerExecutableElement.java
@@ -16,7 +16,7 @@
 
 package dagger.spi.model;
 
-import com.google.devtools.ksp.symbol.KSFunctionDeclaration;
+import com.google.devtools.ksp.symbol.KSDeclaration;
 import com.google.errorprone.annotations.DoNotMock;
 import javax.lang.model.element.ExecutableElement;
 
@@ -31,11 +31,12 @@
   public abstract ExecutableElement javac();
 
   /**
-   * Returns the KSP representation for the executable element.
+   * Returns the KSP representation for the executable element. Can be either KSFunctionDeclaration
+   * or KSPropertyDeclaration.
    *
    * @throws IllegalStateException if the current backend isn't KSP.
    */
-  public abstract KSFunctionDeclaration ksp();
+  public abstract KSDeclaration ksp();
 
   /** Returns the backend used in this compilation. */
   public abstract DaggerProcessingEnv.Backend backend();
diff --git a/java/dagger/testing/compile/CompilerTests.java b/java/dagger/testing/compile/CompilerTests.java
index ac74a61..39d22cb 100644
--- a/java/dagger/testing/compile/CompilerTests.java
+++ b/java/dagger/testing/compile/CompilerTests.java
@@ -68,6 +68,14 @@
       ImmutableMap.of(
           "dagger.experimentalDaggerErrorMessages", "enabled");
 
+  private static final ImmutableList<String> DEFAULT_JAVAC_OPTIONS = ImmutableList.of();
+
+  private static final ImmutableList<String> DEFAULT_KOTLINC_OPTIONS =
+      ImmutableList.of(
+          "-api-version=1.9",
+          "-language-version=1.9",
+          "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true");
+
   /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */
   public static XProcessingEnv.Backend backend(CompilationResultSubject subject) {
     // TODO(bcorso): Create a more official API for this in XProcessing testing.
@@ -136,8 +144,8 @@
           sources(),
           /* classpath= */ ImmutableList.of(),
           processorOptions(),
-          /* javacArguments= */ ImmutableList.of(),
-          /* kotlincArguments= */ ImmutableList.of(),
+          /* javacArguments= */ DEFAULT_JAVAC_OPTIONS,
+          /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS,
           /* config= */ PROCESSING_ENV_CONFIG,
           invocation -> {
             onInvocation.accept(invocation);
@@ -228,9 +236,8 @@
           sources().asList(),
           /* classpath= */ ImmutableList.of(),
           processorOptions(),
-          /* javacArguments= */ ImmutableList.of(),
-          /* kotlincArguments= */ ImmutableList.of(
-              "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"),
+          /* javacArguments= */ DEFAULT_JAVAC_OPTIONS,
+          /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS,
           /* config= */ PROCESSING_ENV_CONFIG,
           /* javacProcessors= */ mergeProcessors(
               ImmutableList.of(
@@ -306,17 +313,18 @@
       Map<String, String> processorOptions,
       TemporaryFolder tempFolder,
       Consumer<TestCompilationResult> onCompilationResult) {
-    TestCompilationResult result = TestKotlinCompilerKt.compile(
-        tempFolder.getRoot(),
-        new TestCompilationArguments(
-            sources,
-            /*classpath=*/ ImmutableList.of(compilerDepsJar()),
-            /*inheritClasspath=*/ false,
-            /*javacArguments=*/ ImmutableList.of(),
-            /*kotlincArguments=*/ ImmutableList.of(),
-            /*kaptProcessors=*/ ImmutableList.of(new ComponentProcessor()),
-            /*symbolProcessorProviders=*/ ImmutableList.of(),
-            /*processorOptions=*/ processorOptions));
+    TestCompilationResult result =
+        TestKotlinCompilerKt.compile(
+            tempFolder.getRoot(),
+            new TestCompilationArguments(
+                sources,
+                /* classpath= */ ImmutableList.of(compilerDepsJar()),
+                /* inheritClasspath= */ false,
+                /* javacArguments= */ DEFAULT_JAVAC_OPTIONS,
+                /* kotlincArguments= */ DEFAULT_KOTLINC_OPTIONS,
+                /* kaptProcessors= */ ImmutableList.of(new ComponentProcessor()),
+                /* symbolProcessorProviders= */ ImmutableList.of(),
+                /* processorOptions= */ processorOptions));
     onCompilationResult.accept(result);
   }
 
diff --git a/java/dagger/testing/compile/macros.bzl b/java/dagger/testing/compile/macros.bzl
index 9543e0e..3338e8a 100644
--- a/java/dagger/testing/compile/macros.bzl
+++ b/java/dagger/testing/compile/macros.bzl
@@ -11,10 +11,10 @@
 # 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.
-
 """Macros for building compiler tests."""
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_binary", "java_test")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 
 def compiler_test(name, size = "large", compiler_deps = None, **kwargs):
     """Generates a java_test that tests java compilation with the given compiler deps.
@@ -35,7 +35,7 @@
 
     # This JAR is loaded at runtime and contains the dependencies used by the compiler during tests.
     # We separate these dependencies from the java_test dependencies to avoid 1 version violations.
-    native.java_binary(
+    java_binary(
         name = name + "_compiler_deps",
         testonly = 1,
         tags = ["notap"],
@@ -54,8 +54,7 @@
     if kwargs.get("srcs", None):
         # Add a dep to allow usage of CompilerTests.
         kwargs["deps"] = kwargs.get("deps", []) + ["//java/dagger/testing/compile"]
-
-    native.java_test(name = name, size = size, **kwargs)
+    java_test(name = name, size = size, **kwargs)
 
 def kt_compiler_test(name, srcs = [], deps = [], **kwargs):
     """Generates a java_test that tests java compilation with the given compiler deps.
diff --git a/javatests/artifacts/dagger-android-ksp/app/build.gradle b/javatests/artifacts/dagger-android-ksp/app/build.gradle
index 434590a..b7634e4 100644
--- a/javatests/artifacts/dagger-android-ksp/app/build.gradle
+++ b/javatests/artifacts/dagger-android-ksp/app/build.gradle
@@ -30,7 +30,7 @@
         versionCode 1
         versionName "1.0"
     }
-
+    namespace "dagger.android.ksp"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_17
         targetCompatibility JavaVersion.VERSION_17
@@ -49,6 +49,10 @@
     }
 }
 
+kotlin {
+    jvmToolchain(17)
+}
+
 dependencies {
     implementation 'androidx.appcompat:appcompat:1.2.0'
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
diff --git a/javatests/artifacts/dagger-android-ksp/build.gradle b/javatests/artifacts/dagger-android-ksp/build.gradle
index 2aa0605..f675791 100644
--- a/javatests/artifacts/dagger-android-ksp/build.gradle
+++ b/javatests/artifacts/dagger-android-ksp/build.gradle
@@ -16,9 +16,9 @@
 
 buildscript {
     ext {
-        agp_version = "8.1.0"
-        kotlin_version = "1.9.20"
-        ksp_version = "$kotlin_version-1.0.14"
+        agp_version = "8.1.1"
+        kotlin_version = "2.0.21"
+        ksp_version = "$kotlin_version-1.0.28"
     }
     repositories {
         google()
diff --git a/javatests/artifacts/dagger-android/simple/app/build.gradle b/javatests/artifacts/dagger-android/simple/app/build.gradle
index 881a304..1f1ceac 100644
--- a/javatests/artifacts/dagger-android/simple/app/build.gradle
+++ b/javatests/artifacts/dagger-android/simple/app/build.gradle
@@ -27,6 +27,7 @@
         versionCode 1
         versionName "1.0"
     }
+    namespace "dagger.android.simple"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
@@ -53,18 +54,18 @@
   annotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
 
   testImplementation 'com.google.truth:truth:1.0.1'
-  testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+  testImplementation 'org.robolectric:robolectric:4.11.1'
   testImplementation 'androidx.core:core:1.3.2'
   testImplementation 'androidx.test.ext:junit:1.1.3'
   testImplementation 'androidx.test:runner:1.4.0'
-  testImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+  testImplementation 'androidx.test.espresso:espresso-core:3.5.1'
   testImplementation 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
   testAnnotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
 
   androidTestImplementation 'com.google.truth:truth:1.0.1'
   androidTestImplementation 'androidx.test.ext:junit:1.1.3'
   androidTestImplementation 'androidx.test:runner:1.4.0'
-  androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+  androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
   androidTestImplementation 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
   androidTestAnnotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
 
diff --git a/javatests/artifacts/dagger-android/simple/build.gradle b/javatests/artifacts/dagger-android/simple/build.gradle
index 54088d3..29d8b96 100644
--- a/javatests/artifacts/dagger-android/simple/build.gradle
+++ b/javatests/artifacts/dagger-android/simple/build.gradle
@@ -16,7 +16,7 @@
 
 buildscript {
     ext {
-        agp_version = System.getenv('AGP_VERSION') ?: "7.1.2"
+        agp_version = System.getenv('AGP_VERSION') ?: "8.1.1"
     }
     repositories {
         google()
diff --git a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
index 98debb8..e1bef7e 100644
--- a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/dagger-ksp/build.gradle b/javatests/artifacts/dagger-ksp/build.gradle
index 35aea20..63b0341 100644
--- a/javatests/artifacts/dagger-ksp/build.gradle
+++ b/javatests/artifacts/dagger-ksp/build.gradle
@@ -17,8 +17,8 @@
 buildscript {
   ext {
     dagger_version = "LOCAL-SNAPSHOT"
-    kotlin_version = "1.9.20"
-    ksp_version = "$kotlin_version-1.0.14"
+    kotlin_version = "2.0.21"
+    ksp_version = "$kotlin_version-1.0.28"
     junit_version = "4.13"
     truth_version = "1.0.1"
   }
diff --git a/javatests/artifacts/dagger/build.gradle b/javatests/artifacts/dagger/build.gradle
index 499b1ee..6c72ef0 100644
--- a/javatests/artifacts/dagger/build.gradle
+++ b/javatests/artifacts/dagger/build.gradle
@@ -17,8 +17,8 @@
 buildscript {
   ext {
     dagger_version = "LOCAL-SNAPSHOT"
-    kotlin_version = "1.9.20"
-    ksp_version = "$kotlin_version-1.0.14"
+    kotlin_version = "2.0.21"
+    ksp_version = "$kotlin_version-1.0.28"
     junit_version = "4.13"
     truth_version = "1.0.1"
   }
diff --git a/javatests/artifacts/dagger/java-app/build.gradle b/javatests/artifacts/dagger/java-app/build.gradle
index 16c6e66..b167746 100644
--- a/javatests/artifacts/dagger/java-app/build.gradle
+++ b/javatests/artifacts/dagger/java-app/build.gradle
@@ -20,8 +20,8 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
 
 dependencies {
diff --git a/javatests/artifacts/dagger/lazyclasskey/app/build.gradle b/javatests/artifacts/dagger/lazyclasskey/app/build.gradle
index b44309a..19fef9c 100644
--- a/javatests/artifacts/dagger/lazyclasskey/app/build.gradle
+++ b/javatests/artifacts/dagger/lazyclasskey/app/build.gradle
@@ -30,7 +30,7 @@
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
-
+    namespace "dagger.lazyclasskey"
     buildTypes {
         debug {
             minifyEnabled true
@@ -56,7 +56,7 @@
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     androidTestImplementation "androidx.test:runner:1.5.2"
     androidTestImplementation "androidx.test:rules:1.5.0"
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
 
     // Dagger dependencies
     implementation "com.google.dagger:dagger:$dagger_version"
diff --git a/javatests/artifacts/dagger/lazyclasskey/app/proguard-rules.pro b/javatests/artifacts/dagger/lazyclasskey/app/proguard-rules.pro
index 9598002..49d9a65 100644
--- a/javatests/artifacts/dagger/lazyclasskey/app/proguard-rules.pro
+++ b/javatests/artifacts/dagger/lazyclasskey/app/proguard-rules.pro
@@ -1,5 +1,9 @@
 
 -dontwarn com.google.errorprone.annotations.MustBeClosed
+# These are rules to enable instrumentation test to run while main app is optimized
  # TODO(b/324097623) Remove the keep rules once test won't be affected by obfuscation
 -keep class kotlin.**
 -keep class javax.** { *; }
+-keep class com.google.common.util.concurrent.ListenableFuture {
+    <methods>;
+}
diff --git a/javatests/artifacts/dagger/lazyclasskey/build.gradle b/javatests/artifacts/dagger/lazyclasskey/build.gradle
index a0d4252..16982d4 100644
--- a/javatests/artifacts/dagger/lazyclasskey/build.gradle
+++ b/javatests/artifacts/dagger/lazyclasskey/build.gradle
@@ -17,9 +17,8 @@
 buildscript {
     ext {
         dagger_version = 'LOCAL-SNAPSHOT'
-        // AGP is set below 7.2.0 on purpose to be able to obfuscate debug apk.
-        agp_version = "7.1.2"
-        kotlin_version = '1.9.20'
+        agp_version = "8.1.1"
+        kotlin_version = '2.0.21'
     }
     repositories {
         google()
diff --git a/javatests/artifacts/dagger/lazyclasskey/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
index 9623276..707e21e 100644
--- a/javatests/artifacts/dagger/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/dagger/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 networkTimeout=10000
 validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/build.gradle
index 22933a4..0b0cec9 100644
--- a/javatests/artifacts/dagger/transitive-annotation-app/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-app/build.gradle
@@ -20,8 +20,8 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
 
 dependencies {
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle
index 2126f09..60259e5 100644
--- a/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library1/build.gradle
@@ -20,8 +20,8 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
 
 dependencies {
diff --git a/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle b/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle
index b4d45e4..c0a95b9 100644
--- a/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-app/library2/build.gradle
@@ -20,6 +20,6 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle
index 1b0c04d..88519e9 100644
--- a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle
@@ -21,8 +21,8 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
 
 kapt {
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle
index 3875913..17c63b3 100644
--- a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle
@@ -21,8 +21,8 @@
 }
 
 java {
-  // Make sure the generated source is compatible with Java 7.
-  sourceCompatibility = JavaVersion.VERSION_1_7
+  // Make sure the generated source is compatible with Java 8.
+  sourceCompatibility = JavaVersion.VERSION_1_8
 }
 
 kapt {
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle
index 9b4c087..e65b5bd 100644
--- a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle
@@ -25,6 +25,6 @@
 }
 
 java {
-    // Make sure the generated source is compatible with Java 7.
-    sourceCompatibility = JavaVersion.VERSION_1_7
+    // Make sure the generated source is compatible with Java 8.
+    sourceCompatibility = JavaVersion.VERSION_1_8
 }
diff --git a/javatests/artifacts/hilt-android/lazyclasskey/app/build.gradle b/javatests/artifacts/hilt-android/lazyclasskey/app/build.gradle
index 0f854cb..45c1aa9 100644
--- a/javatests/artifacts/hilt-android/lazyclasskey/app/build.gradle
+++ b/javatests/artifacts/hilt-android/lazyclasskey/app/build.gradle
@@ -31,7 +31,7 @@
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
-
+    namespace "hilt.lazyclasskey"
     buildTypes {
         debug {
             minifyEnabled true
@@ -57,7 +57,7 @@
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     androidTestImplementation "androidx.test:runner:1.5.2"
     androidTestImplementation "androidx.test:rules:1.5.0"
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
 
     // Hilt dependencies
     implementation "com.google.dagger:hilt-android:$hilt_version"
diff --git a/javatests/artifacts/hilt-android/lazyclasskey/app/proguard-rules.pro b/javatests/artifacts/hilt-android/lazyclasskey/app/proguard-rules.pro
index d389c43..cd04bbb 100644
--- a/javatests/artifacts/hilt-android/lazyclasskey/app/proguard-rules.pro
+++ b/javatests/artifacts/hilt-android/lazyclasskey/app/proguard-rules.pro
@@ -1,3 +1,7 @@
 -dontwarn com.google.errorprone.annotations.MustBeClosed
- # TODO(b/324097623) Remove the keep rules once test won't be affected by obfuscation
--keep class kotlin.**
\ No newline at end of file
+# These are rules to enable instrumentation test to run while main app is optimized
+# TODO(b/324097623) Remove the keep rules once test won't be affected by obfuscation
+-keep class kotlin.**
+-keep class com.google.common.util.concurrent.ListenableFuture {
+    <methods>;
+}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/lazyclasskey/build.gradle b/javatests/artifacts/hilt-android/lazyclasskey/build.gradle
index 14bbfbd..53ced2c 100644
--- a/javatests/artifacts/hilt-android/lazyclasskey/build.gradle
+++ b/javatests/artifacts/hilt-android/lazyclasskey/build.gradle
@@ -17,9 +17,8 @@
 buildscript {
     ext {
         hilt_version = 'LOCAL-SNAPSHOT'
-        // AGP is set below 7.2.0 on purpose to be able to obfuscate debug apk.
-        agp_version = "7.1.2"
-        kotlin_version = '1.9.20'
+        agp_version = "8.1.1"
+        kotlin_version = '2.0.21'
     }
     repositories {
         google()
diff --git a/javatests/artifacts/hilt-android/lazyclasskey/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
index 9623276..707e21e 100644
--- a/javatests/artifacts/hilt-android/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/lazyclasskey/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 networkTimeout=10000
 validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
diff --git a/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle b/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle
index e4cde41..632e68e 100644
--- a/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle
+++ b/javatests/artifacts/hilt-android/pluginMarker/app/build.gradle
@@ -15,7 +15,7 @@
  */
 
 plugins {
-    id 'com.android.application' version '7.0.0'
+    id 'com.android.application' version '8.1.1'
     id 'com.google.dagger.hilt.android' version 'LOCAL-SNAPSHOT'
 }
 
@@ -28,7 +28,7 @@
         minSdkVersion 16
         targetSdkVersion 33
     }
-
+    namespace "dagger.hilt.android.simple"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties
index 98debb8..e1bef7e 100644
--- a/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/pluginMarker/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle b/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle
index 7a156ef..deedbef 100644
--- a/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/app-java-only/build.gradle
@@ -19,7 +19,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         applicationId "dagger.hilt.android.simple"
@@ -27,8 +27,8 @@
         targetSdkVersion 33
         versionCode 1
         versionName "1.0"
-        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
+    namespace "dagger.hilt.android.simple"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
@@ -61,9 +61,9 @@
 
   testImplementation 'com.google.truth:truth:1.0.1'
   testImplementation 'junit:junit:4.13'
-  testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+  testImplementation 'org.robolectric:robolectric:4.11.1'
   testImplementation 'androidx.core:core:1.3.2'
   testImplementation 'androidx.test.ext:junit:1.1.3'
   testImplementation 'androidx.test:runner:1.4.0'
-  testImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+  testImplementation 'androidx.test.espresso:espresso-core:3.5.1'
 }
diff --git a/javatests/artifacts/hilt-android/simple/app/build.gradle b/javatests/artifacts/hilt-android/simple/app/build.gradle
index 8a196cf..c0fde10 100644
--- a/javatests/artifacts/hilt-android/simple/app/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/app/build.gradle
@@ -44,7 +44,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         applicationId "dagger.hilt.android.simple"
@@ -54,6 +54,7 @@
         versionName "1.0"
         testInstrumentationRunner "dagger.hilt.android.simple.SimpleEmulatorTestRunner"
     }
+    namespace "dagger.hilt.android.simple"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
@@ -108,11 +109,11 @@
 
   testImplementation 'com.google.truth:truth:1.0.1'
   testImplementation 'junit:junit:4.13'
-  testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+  testImplementation 'org.robolectric:robolectric:4.11.1'
   testImplementation 'androidx.core:core:1.3.2'
   testImplementation 'androidx.test.ext:junit:1.1.3'
   testImplementation 'androidx.test:runner:1.4.0'
-  testImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+  testImplementation 'androidx.test.espresso:espresso-core:3.5.1'
   testImplementation "com.google.dagger:hilt-android-testing:$dagger_version"
   testAnnotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
 
@@ -120,7 +121,7 @@
   androidTestImplementation 'junit:junit:4.13'
   androidTestImplementation 'androidx.test.ext:junit:1.1.3'
   androidTestImplementation 'androidx.test:runner:1.4.0'
-  androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+  androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
   androidTestImplementation "com.google.dagger:hilt-android-testing:$dagger_version"
   androidTestAnnotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
 
diff --git a/javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java b/javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java
deleted file mode 100644
index 265869a..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/androidTest-agp-4.2.0/java/dagger/hilt/android/simple/BroadcastReceiverTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger 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
- *
- * 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 dagger.hilt.android.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A injection test of Broadcast receivers */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public class BroadcastReceiverTest {
-
-  @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
-  @BindValue final String valueToInject = "test value";
-
-  @Test
-  public void verifyReceiverInjectedValue() throws InterruptedException {
-    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-    TestReceiverOne receiver = new TestReceiverOne();
-    IntentFilter intentFilter = new IntentFilter("test-action");
-    context.registerReceiver(receiver, intentFilter);
-
-    Intent intent = new Intent();
-    intent.setAction("test-action");
-    context.sendBroadcast(intent);
-
-    receiver.latch.await(2, TimeUnit.SECONDS);
-    assertThat(receiver.injectedValue).isNotEmpty();
-  }
-
-  @Test
-  public void verifyBaseReceiverInjectedValue() throws InterruptedException {
-    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-    TestReceiverTwo receiver = new TestReceiverTwo();
-    IntentFilter intentFilter = new IntentFilter("test-action");
-    context.registerReceiver(receiver, intentFilter);
-
-    Intent intent = new Intent();
-    intent.setAction("test-action");
-    context.sendBroadcast(intent);
-
-    receiver.latch.await(2, TimeUnit.SECONDS);
-    assertThat(receiver.injectedValue).isNotEmpty();
-  }
-
-  @Test
-  public void verifyBaseReceiverIsNotDoubleInjected() throws InterruptedException {
-    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-    TestReceiverThree receiver = new TestReceiverThree();
-    IntentFilter intentFilter = new IntentFilter("test-action");
-    context.registerReceiver(receiver, intentFilter);
-
-    Intent intent = new Intent();
-    intent.setAction("test-action");
-    context.sendBroadcast(intent);
-
-    receiver.latch.await(2, TimeUnit.SECONDS);
-    assertThat(receiver.injectedValue).isNotEmpty();
-    assertThat(receiver.onReceiveCalled).isEqualTo(1);
-  }
-
-  @Test
-  public void verifyComplexReceiverInjectedValue() throws InterruptedException {
-    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-    TestReceiverFour receiver = new TestReceiverFour();
-    IntentFilter intentFilter = new IntentFilter("test-action");
-    context.registerReceiver(receiver, intentFilter);
-
-    Intent intent = new Intent();
-    intent.setAction("test-action");
-    context.sendBroadcast(intent);
-
-    receiver.latch.await(2, TimeUnit.SECONDS);
-    assertThat(receiver.injectedValue).isNotEmpty();
-  }
-
-  /** Test receiver */
-  @AndroidEntryPoint
-  public static class TestReceiverOne extends BroadcastReceiver {
-
-    final CountDownLatch latch = new CountDownLatch(1);
-
-    @Inject
-    String injectedValue;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      latch.countDown();
-    }
-  }
-
-  /** Test receiver */
-  @AndroidEntryPoint
-  public static class TestReceiverTwo extends BaseReceiverAbstractMethod {
-
-    final CountDownLatch latch = new CountDownLatch(1);
-
-    @Inject
-    String injectedValue;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      latch.countDown();
-    }
-  }
-
-  /** Test receiver */
-  @AndroidEntryPoint
-  public static class TestReceiverThree extends BaseReceiverConcreteMethod {
-
-    final CountDownLatch latch = new CountDownLatch(1);
-
-    @Inject
-    String injectedValue;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      super.onReceive(context, intent);
-      latch.countDown();
-    }
-  }
-
-  /** Complex-ish test receiver */
-  @AndroidEntryPoint
-  public static class TestReceiverFour extends BroadcastReceiver {
-
-    final CountDownLatch latch = new CountDownLatch(1);
-
-    @Inject String injectedValue;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      // Weird code, but it tests that the exception table and stack table frames are correctly
-      // updated in a transformation.
-      boolean var0;
-      if (context != null) {
-        var0 = false;
-        Object var1 = context.getClass();
-        try {
-          throw new IllegalStateException();
-        } catch (IllegalStateException ex) {
-          var0 = true;
-        }
-      } else {
-        BroadcastReceiver myself = this;
-        var0 = false;
-      }
-      latch.countDown();
-    }
-  }
-
-  /** Base test receiver */
-  abstract static class BaseReceiverAbstractMethod extends BroadcastReceiver {
-
-  }
-
-  /** Base test receiver */
-  abstract static class BaseReceiverConcreteMethod extends BroadcastReceiver {
-
-    int onReceiveCalled = 0;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      onReceiveCalled++;
-    }
-  }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml
index 0b12b13..e77499f 100644
--- a/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml
+++ b/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml
@@ -14,6 +14,7 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:tools="http://schemas.android.com/tools"
   package="dagger.hilt.android.simple">
 
   <application android:name=".SimpleApplication" android:label="@string/appName">
@@ -31,5 +32,11 @@
         android:theme="@style/Theme.AppCompat.Light"
         android:exported="false">
     </activity>
+    <!-- WM is brought due to andridx.hilt:hilt-work but we don't need it, disable it. -->
+     <provider
+        android:name="androidx.work.impl.WorkManagerInitializer"
+        android:authorities="${applicationId}.workmanager-init"
+        tools:node="remove">
+     </provider>
   </application>
 </manifest>
diff --git a/javatests/artifacts/hilt-android/simple/build.gradle b/javatests/artifacts/hilt-android/simple/build.gradle
index e0f39a3..3dfb1b9 100644
--- a/javatests/artifacts/hilt-android/simple/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/build.gradle
@@ -17,8 +17,8 @@
 buildscript {
     ext {
         dagger_version = 'LOCAL-SNAPSHOT'
-        kotlin_version = '1.9.20'
-        agp_version = System.getenv('AGP_VERSION') ?: "7.1.2"
+        kotlin_version = '2.0.21'
+        agp_version = System.getenv('AGP_VERSION') ?: "8.1.1"
     }
     repositories {
         google()
diff --git a/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle
index ab5424e..ada7b6a 100644
--- a/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle
@@ -5,7 +5,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -13,7 +13,7 @@
         versionCode 1
         versionName "1.0"
     }
-
+    namespace "dagger.hilt.android.simple.deep"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle b/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle
index 22f815c..3f8223c 100644
--- a/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle
@@ -3,8 +3,8 @@
 }
 
 java {
-    sourceCompatibility = JavaVersion.VERSION_1_7
-    targetCompatibility = JavaVersion.VERSION_1_7
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
 }
 
 dependencies {
diff --git a/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle b/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle
index 2a36e6f..615cd86 100644
--- a/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/earlyentrypoint/build.gradle
@@ -5,7 +5,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -13,6 +13,7 @@
         versionCode 1
         versionName "1.0"
     }
+    namespace "dagger.hilt.android.simple.earlyentrypoint"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
@@ -59,7 +60,7 @@
 
     testImplementation 'com.google.truth:truth:1.0.1'
     testImplementation 'junit:junit:4.13'
-    testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+    testImplementation 'org.robolectric:robolectric:4.11.1'
     testImplementation 'androidx.core:core:1.3.2'
     testImplementation 'androidx.test.ext:junit:1.1.3'
     testImplementation 'androidx.test:runner:1.4.0'
diff --git a/javatests/artifacts/hilt-android/simple/feature/build.gradle b/javatests/artifacts/hilt-android/simple/feature/build.gradle
index dd33e29..e3fbea2 100644
--- a/javatests/artifacts/hilt-android/simple/feature/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/feature/build.gradle
@@ -21,7 +21,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -29,6 +29,7 @@
         versionCode 1
         versionName "1.0"
     }
+    namespace "dagger.hilt.android.simple.feature"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
@@ -44,6 +45,10 @@
     }
 }
 
+kotlin {
+    jvmToolchain(11)
+}
+
 kapt {
  correctErrorTypes true
 }
diff --git a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
index 98debb8..e1bef7e 100644
--- a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/simple/uitest/build.gradle b/javatests/artifacts/hilt-android/simple/uitest/build.gradle
index 7c4e0fd..2b10c39 100644
--- a/javatests/artifacts/hilt-android/simple/uitest/build.gradle
+++ b/javatests/artifacts/hilt-android/simple/uitest/build.gradle
@@ -19,7 +19,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -27,6 +27,7 @@
         testInstrumentationRunner "dagger.hilt.android.simple.uitest.TestRunner"
         missingDimensionStrategy 'tier', 'free'
     }
+    namespace "dagger.hilt.android.simple.uitest"
     targetProjectPath ':app'
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
index 1e83543..18047e5 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
@@ -7,7 +7,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -15,6 +15,7 @@
         versionCode 1
         versionName "1.0"
     }
+    namespace "dagger.hilt.android.simpleKotlin.lib"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
index fe4f5b4..8495196 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
@@ -22,7 +22,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         applicationId "dagger.hilt.android.simpleKotlin"
@@ -32,6 +32,7 @@
         versionName "1.0"
         testInstrumentationRunner "dagger.hilt.android.example.gradle.simpleKotlin.TestRunner"
     }
+    namespace "dagger.hilt.android.simpleKotlin"
     buildTypes {
         release {
             minifyEnabled true
@@ -99,7 +100,7 @@
     testImplementation 'androidx.test:runner:1.4.0'
     testImplementation 'com.google.truth:truth:1.0.1'
     testImplementation 'junit:junit:4.13'
-    testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
+    testImplementation 'org.robolectric:robolectric:4.11.1'
     testImplementation 'androidx.core:core:1.3.2'
     // TODO(bcorso): This multidex dep shouldn't be required -- it's a dep for the generated code.
     testImplementation 'androidx.multidex:multidex:2.0.0'
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
index 3773deb..b109613 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
@@ -16,9 +16,9 @@
 
 buildscript {
     ext {
-        kotlin_version = '1.9.20'
-        ksp_version = "$kotlin_version-1.0.14"
-        agp_version = System.getenv('AGP_VERSION') ?: "7.1.2"
+        kotlin_version = '2.0.21'
+        ksp_version = "$kotlin_version-1.0.28"
+        agp_version = System.getenv('AGP_VERSION') ?: "8.1.1"
     }
     repositories {
         google()
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
index 8973bb9..c0ccb16 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
@@ -8,7 +8,7 @@
 
 android {
     compileSdkVersion 33
-    buildToolsVersion "33.0.0"
+    buildToolsVersion "33.0.1"
 
     defaultConfig {
         minSdkVersion 16
@@ -18,6 +18,7 @@
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
+    namespace "dagger.hilt.android.simpleKotlin.deep"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_11
         targetCompatibility JavaVersion.VERSION_11
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
index 98debb8..e1bef7e 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/viewmodel/app/build.gradle b/javatests/artifacts/hilt-android/viewmodel/app/build.gradle
index a212b3c..d7e8ba8 100644
--- a/javatests/artifacts/hilt-android/viewmodel/app/build.gradle
+++ b/javatests/artifacts/hilt-android/viewmodel/app/build.gradle
@@ -57,7 +57,7 @@
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     androidTestImplementation "androidx.test:runner:1.5.2"
     androidTestImplementation "androidx.test:rules:1.5.0"
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
 
     // Hilt dependencies
     implementation "com.google.dagger:hilt-android:$hilt_version"
diff --git a/javatests/artifacts/hilt-android/viewmodel/app/proguard-rules.pro b/javatests/artifacts/hilt-android/viewmodel/app/proguard-rules.pro
index 0929028..da9e79c 100644
--- a/javatests/artifacts/hilt-android/viewmodel/app/proguard-rules.pro
+++ b/javatests/artifacts/hilt-android/viewmodel/app/proguard-rules.pro
@@ -1,2 +1,7 @@
 -dontwarn com.google.errorprone.annotations.MustBeClosed
+# These are rules to enable instrumentation test to run while main app is optimized
+ # TODO(b/324097623) Remove the keep rules once test won't be affected by obfuscation
 -keep class kotlin.**
+-keep class com.google.common.util.concurrent.ListenableFuture {
+    <methods>;
+}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/viewmodel/build.gradle b/javatests/artifacts/hilt-android/viewmodel/build.gradle
index bbcc108..cb70181 100644
--- a/javatests/artifacts/hilt-android/viewmodel/build.gradle
+++ b/javatests/artifacts/hilt-android/viewmodel/build.gradle
@@ -17,9 +17,8 @@
 buildscript {
     ext {
         hilt_version = 'LOCAL-SNAPSHOT'
-        // AGP is set below 7.2.0 on purpose to be able to obfuscate debug apk.
-        agp_version = "7.1.2"
-        kotlin_version = '1.9.20'
+        agp_version = "8.1.1"
+        kotlin_version = '2.0.21'
     }
     repositories {
         google()
@@ -29,7 +28,7 @@
     dependencies {
         classpath "com.android.tools.build:gradle:$agp_version"
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-	classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
+        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
     }
 }
 
diff --git a/javatests/artifacts/hilt-android/viewmodel/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/viewmodel/gradle/wrapper/gradle-wrapper.properties
index 9623276..707e21e 100644
--- a/javatests/artifacts/hilt-android/viewmodel/gradle/wrapper/gradle-wrapper.properties
+++ b/javatests/artifacts/hilt-android/viewmodel/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 networkTimeout=10000
 validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
diff --git a/javatests/dagger/android/AndroidInjectionTest.java b/javatests/dagger/android/AndroidInjectionTest.java
index 499e981..5fa3951 100644
--- a/javatests/dagger/android/AndroidInjectionTest.java
+++ b/javatests/dagger/android/AndroidInjectionTest.java
@@ -30,7 +30,6 @@
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.LooperMode;
-import org.robolectric.util.FragmentTestUtil;
 
 @LooperMode(LEGACY)
 @RunWith(AndroidJUnit4.class)
@@ -133,7 +132,8 @@
   @Test
   public void injectFragment_hasFragmentInjectorNotFound() {
     Fragment fragment = new Fragment();
-    FragmentTestUtil.startFragment(fragment);
+    Activity activity = Robolectric.setupActivity(Activity.class);
+    activity.getFragmentManager().beginTransaction().add(fragment, null).commit();
 
     try {
       AndroidInjection.inject(fragment);
@@ -167,7 +167,8 @@
   @Config(application = ApplicationReturnsNull.class)
   public void fragmentInjector_returnsNull() {
     Fragment fragment = new Fragment();
-    FragmentTestUtil.startFragment(fragment);
+    Activity activity = Robolectric.setupActivity(Activity.class);
+    activity.getFragmentManager().beginTransaction().add(fragment, null).commit();
 
     try {
       AndroidInjection.inject(fragment);
diff --git a/javatests/dagger/android/processor/BUILD b/javatests/dagger/android/processor/BUILD
index 518234d..ddf930b 100644
--- a/javatests/dagger/android/processor/BUILD
+++ b/javatests/dagger/android/processor/BUILD
@@ -36,7 +36,7 @@
         "//third_party/java/guava/collect",
         "//third_party/java/junit",
         "//third_party/java/truth",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_activity_activity",
         "@maven//:androidx_fragment_fragment",
         "@maven//:androidx_lifecycle_lifecycle_common",
diff --git a/javatests/dagger/functional/assisted/subpackage/BUILD b/javatests/dagger/functional/assisted/subpackage/BUILD
index 8f06984..a07c163 100644
--- a/javatests/dagger/functional/assisted/subpackage/BUILD
+++ b/javatests/dagger/functional/assisted/subpackage/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Functional tests for Dagger
 
+load("@rules_java//java:defs.bzl", "java_library")
+
 package(default_visibility = ["//:src"])
 
 java_library(
diff --git a/javatests/dagger/functional/basic/BasicTest.java b/javatests/dagger/functional/basic/BasicTest.java
index a3e4419..a4e26e8 100644
--- a/javatests/dagger/functional/basic/BasicTest.java
+++ b/javatests/dagger/functional/basic/BasicTest.java
@@ -61,23 +61,23 @@
   }
 
   @Theory public void boxedPrimitives(BasicComponent basicComponent) {
-    assertThat(basicComponent.getBoxedByte()).isEqualTo(new Byte(BOUND_BYTE));
-    assertThat(basicComponent.getBoxedChar()).isEqualTo(new Character(BOUND_CHAR));
-    assertThat(basicComponent.getBoxedShort()).isEqualTo(new Short(BOUND_SHORT));
-    assertThat(basicComponent.getBoxedInt()).isEqualTo(new Integer(BOUND_INT));
-    assertThat(basicComponent.getBoxedLong()).isEqualTo(new Long(BOUND_LONG));
-    assertThat(basicComponent.getBoxedBoolean()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+    assertThat(basicComponent.getBoxedByte()).isEqualTo(BOUND_BYTE);
+    assertThat(basicComponent.getBoxedChar()).isEqualTo(BOUND_CHAR);
+    assertThat(basicComponent.getBoxedShort()).isEqualTo(BOUND_SHORT);
+    assertThat(basicComponent.getBoxedInt()).isEqualTo(BOUND_INT);
+    assertThat(basicComponent.getBoxedLong()).isEqualTo(BOUND_LONG);
+    assertThat(basicComponent.getBoxedBoolean()).isEqualTo(BOUND_BOOLEAN);
     assertThat(basicComponent.getBoxedFloat()).isEqualTo(BOUND_FLOAT);
     assertThat(basicComponent.getBoxedDouble()).isEqualTo(BOUND_DOUBLE);
   }
 
   @Theory public void boxedPrimitiveProviders(BasicComponent basicComponent) {
-    assertThat(basicComponent.getByteProvider().get()).isEqualTo(new Byte(BOUND_BYTE));
-    assertThat(basicComponent.getCharProvider().get()).isEqualTo(new Character(BOUND_CHAR));
-    assertThat(basicComponent.getShortProvider().get()).isEqualTo(new Short(BOUND_SHORT));
-    assertThat(basicComponent.getIntProvider().get()).isEqualTo(new Integer(BOUND_INT));
-    assertThat(basicComponent.getLongProvider().get()).isEqualTo(new Long(BOUND_LONG));
-    assertThat(basicComponent.getBooleanProvider().get()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+    assertThat(basicComponent.getByteProvider().get()).isEqualTo(BOUND_BYTE);
+    assertThat(basicComponent.getCharProvider().get()).isEqualTo(BOUND_CHAR);
+    assertThat(basicComponent.getShortProvider().get()).isEqualTo(BOUND_SHORT);
+    assertThat(basicComponent.getIntProvider().get()).isEqualTo(BOUND_INT);
+    assertThat(basicComponent.getLongProvider().get()).isEqualTo(BOUND_LONG);
+    assertThat(basicComponent.getBooleanProvider().get()).isEqualTo(BOUND_BOOLEAN);
     assertThat(basicComponent.getFloatProvider().get()).isEqualTo(BOUND_FLOAT);
     assertThat(basicComponent.getDoubleProvider().get()).isEqualTo(BOUND_DOUBLE);
   }
diff --git a/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java b/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java
index 83505e9..2dd16f2 100644
--- a/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java
+++ b/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java
@@ -17,6 +17,7 @@
 package dagger.functional.factory;
 
 import static com.google.common.truth.Truth.assertThat;
+import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -60,7 +61,7 @@
     }
   }
 
-  @Target({METHOD, PARAMETER})
+  @Target({METHOD, PARAMETER, FIELD})
   @Retention(RUNTIME)
   @interface Nullable {}
 
diff --git a/javatests/dagger/functional/jakarta/BUILD b/javatests/dagger/functional/jakarta/BUILD
index 9feb5e2..8d98d86 100644
--- a/javatests/dagger/functional/jakarta/BUILD
+++ b/javatests/dagger/functional/jakarta/BUILD
@@ -32,3 +32,16 @@
         "@maven//:jakarta_inject_jakarta_inject_api",
     ],
 )
+
+GenJavaTests(
+    name = "JakartaProviderTest",
+    srcs = ["JakartaProviderTest.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/guava/base",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+        "@maven//:jakarta_inject_jakarta_inject_api",
+    ],
+)
diff --git a/javatests/dagger/functional/jakarta/JakartaProviderTest.java b/javatests/dagger/functional/jakarta/JakartaProviderTest.java
new file mode 100644
index 0000000..0c22861
--- /dev/null
+++ b/javatests/dagger/functional/jakarta/JakartaProviderTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.functional.jakarta;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Optional;
+import dagger.Binds;
+import dagger.BindsOptionalOf;
+import dagger.Component;
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.StringKey;
+import jakarta.inject.Inject;
+import jakarta.inject.Provider;
+import jakarta.inject.Qualifier;
+import jakarta.inject.Scope;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class JakartaProviderTest {
+
+  @Scope
+  public @interface TestScope {}
+
+  @Qualifier
+  public @interface TestQualifier {}
+
+  @TestScope
+  @Component(modules = TestModule.class)
+  interface TestComponent {
+    Provider<Foo> getJakartaFoo();
+
+    javax.inject.Provider<Foo> getJavaxFoo();
+
+    Provider<Bar> getJakartaBar();
+
+    javax.inject.Provider<Bar> getJavaxBar();
+
+    @TestQualifier
+    Provider<Foo> getJakartaQualifiedFoo();
+
+    @TestQualifier
+    javax.inject.Provider<Foo> getJavaxQualifiedFoo();
+
+    @TestQualifier
+    Provider<Bar> getJakartaQualifiedBar();
+
+    @TestQualifier
+    javax.inject.Provider<Bar> getJavaxQualifiedBar();
+
+    InjectUsages injectUsages();
+
+    Map<String, Provider<Bar>> getJakartaProviderMap();
+
+    Map<String, javax.inject.Provider<Bar>> getJavaxProviderMap();
+
+    Map<String, Provider<Lazy<Bar>>> getJakartaProviderLazyMap();
+
+    Map<String, javax.inject.Provider<Lazy<Bar>>> getJavaxProviderLazyMap();
+
+    Map<Long, Provider<Long>> getManuallyProvidedJakartaMap();
+
+    Map<Long, javax.inject.Provider<Long>> getManuallyProvidedJavaxMap();
+
+    Optional<Provider<String>> getPresentOptionalJakartaProvider();
+
+    Optional<javax.inject.Provider<String>> getPresentOptionalJavaxProvider();
+
+    Optional<Provider<Long>> getEmptyOptionalJakartaProvider();
+
+    Optional<javax.inject.Provider<Long>> getEmptyOptionalJavaxProvider();
+  }
+
+  public static final class Foo {
+    @Inject
+    Foo() {}
+  }
+
+  @TestScope
+  public static final class Bar {
+    @Inject
+    Bar() {}
+  }
+
+  public static final class InjectUsages {
+    Provider<Bar> jakartaBar;
+    Provider<Bar> jakartaQualifiedBar;
+    javax.inject.Provider<Bar> javaxQualifiedBar;
+
+    @Inject
+    InjectUsages(Provider<Bar> jakartaBar) {
+      this.jakartaBar = jakartaBar;
+    }
+
+    @Inject javax.inject.Provider<Bar> javaxBar;
+
+    @Inject
+    void injectBar(
+        Provider<Bar> jakartaQualifiedBar, javax.inject.Provider<Bar> javaxQualifiedBar) {
+      this.jakartaQualifiedBar = jakartaQualifiedBar;
+      this.javaxQualifiedBar = javaxQualifiedBar;
+    }
+  }
+
+  @Module
+  abstract static class TestModule {
+    @Provides
+    @TestQualifier
+    static Foo provideFoo(
+        Provider<Foo> fooProvider, javax.inject.Provider<Foo> unusedOtherFooProvider) {
+      return fooProvider.get();
+    }
+
+    @Provides
+    @TestQualifier
+    @TestScope
+    static Bar provideBar(
+        Provider<Bar> unusedBarProvider, javax.inject.Provider<Bar> otherBarProvider) {
+      // Use the other one in this case just to vary it from Foo
+      return otherBarProvider.get();
+    }
+
+    @Binds
+    @IntoMap
+    @StringKey("bar")
+    abstract Bar bindBarIntoMap(Bar bar);
+
+    // TODO(b/65118638): Use @Binds @IntoMap Lazy<T> once that works properly.
+    @Provides
+    @IntoMap
+    @StringKey("bar")
+    static Lazy<Bar> provideLazyIntoMap(Lazy<Bar> bar) {
+      return bar;
+    }
+
+    // Manually provide two Provider maps to make sure they don't conflict.
+    @Provides
+    static Map<Long, Provider<Long>> manuallyProvidedJakartaMap() {
+      Map<Long, Provider<Long>> map = new HashMap<>();
+      map.put(9L, null);
+      return map;
+    }
+
+    @Provides
+    static Map<Long, javax.inject.Provider<Long>> manuallyProvidedJavaxMap() {
+      Map<Long, javax.inject.Provider<Long>> map = new HashMap<>();
+      map.put(0L, null);
+      return map;
+    }
+
+    @BindsOptionalOf
+    abstract String bindOptionalString();
+
+    @Provides
+    static String provideString() {
+      return "present";
+    }
+
+    @BindsOptionalOf
+    abstract Long bindOptionalLong();
+  }
+
+  @Test
+  public void testJakartaProviders() {
+    TestComponent testComponent = DaggerJakartaProviderTest_TestComponent.create();
+
+    assertThat(testComponent.getJakartaFoo().get()).isNotNull();
+    assertThat(testComponent.getJavaxFoo().get()).isNotNull();
+
+    assertThat(testComponent.getJakartaBar().get())
+        .isSameInstanceAs(testComponent.getJavaxBar().get());
+
+    assertThat(testComponent.getJakartaQualifiedFoo().get()).isNotNull();
+    assertThat(testComponent.getJavaxQualifiedFoo().get()).isNotNull();
+
+    assertThat(testComponent.getJakartaQualifiedBar().get())
+        .isSameInstanceAs(testComponent.getJavaxQualifiedBar().get());
+    assertThat(testComponent.getJakartaBar().get())
+        .isSameInstanceAs(testComponent.getJakartaQualifiedBar().get());
+
+    InjectUsages injectUsages = testComponent.injectUsages();
+
+    assertThat(injectUsages.jakartaBar.get()).isSameInstanceAs(injectUsages.javaxBar.get());
+    assertThat(injectUsages.jakartaQualifiedBar.get())
+        .isSameInstanceAs(injectUsages.javaxQualifiedBar.get());
+    assertThat(injectUsages.jakartaBar.get())
+        .isSameInstanceAs(injectUsages.jakartaQualifiedBar.get());
+
+    assertThat(testComponent.getJakartaProviderMap().get("bar").get()).isSameInstanceAs(
+        testComponent.getJavaxProviderMap().get("bar").get());
+
+    assertThat(testComponent.getJakartaProviderLazyMap().get("bar").get().get()).isSameInstanceAs(
+        testComponent.getJavaxProviderLazyMap().get("bar").get().get());
+
+    Map<Long, Provider<Long>> manualJakartaMap = testComponent.getManuallyProvidedJakartaMap();
+    assertThat(manualJakartaMap.keySet()).containsExactly(9L);
+
+    Map<Long, javax.inject.Provider<Long>> manualJavaxMap =
+        testComponent.getManuallyProvidedJavaxMap();
+    assertThat(manualJavaxMap.keySet()).containsExactly(0L);
+
+    assertThat(testComponent.getPresentOptionalJakartaProvider().get().get()).isEqualTo("present");
+    assertThat(testComponent.getPresentOptionalJavaxProvider().get().get()).isEqualTo("present");
+    assertThat(testComponent.getEmptyOptionalJakartaProvider().isPresent()).isFalse();
+    assertThat(testComponent.getEmptyOptionalJavaxProvider().isPresent()).isFalse();
+  }
+}
diff --git a/javatests/dagger/functional/jdk8/BUILD b/javatests/dagger/functional/jdk8/BUILD
index 5a2b613..f65f58b 100644
--- a/javatests/dagger/functional/jdk8/BUILD
+++ b/javatests/dagger/functional/jdk8/BUILD
@@ -15,6 +15,7 @@
 # Description:
 #   Functional tests for Dagger that depend on Guava
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
 load("//:test_defs.bzl", "GenJavaTests")
 
diff --git a/javatests/dagger/functional/kotlin/BUILD b/javatests/dagger/functional/kotlin/BUILD
index 49bc2ee..345842d 100644
--- a/javatests/dagger/functional/kotlin/BUILD
+++ b/javatests/dagger/functional/kotlin/BUILD
@@ -15,8 +15,8 @@
 # Description:
 #   Functional test code for Dagger-Android
 
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 load("@rules_java//java:defs.bzl", "java_library")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
 load("//:test_defs.bzl", "GenJavaTests")
 
 package(default_visibility = ["//:src"])
diff --git a/javatests/dagger/functional/kotlin/PropertyQualifierClasses.kt b/javatests/dagger/functional/kotlin/PropertyQualifierClasses.kt
index f6b230f..e39c206 100644
--- a/javatests/dagger/functional/kotlin/PropertyQualifierClasses.kt
+++ b/javatests/dagger/functional/kotlin/PropertyQualifierClasses.kt
@@ -26,56 +26,40 @@
 @Component(modules = [TestKotlinModuleWithQualifier::class])
 interface TestKotlinComponentWithQualifier {
   fun inject(testInjectedClassWithQualifier: TestMemberInjectedClassWithQualifier)
+
   fun inject(fooWithInjectedQualifier: FooWithInjectedQualifier)
 }
 
 @Module
 class TestKotlinModuleWithQualifier {
-  @Provides
-  @JavaTestQualifier
-  fun provideJavaDataA() = TestDataA("test")
+  @Provides @JavaTestQualifier fun provideJavaDataA() = TestDataA("test")
 
-  @Provides
-  @JavaTestQualifier
-  fun provideJavaDataB() = TestDataB("test")
+  @Provides @JavaTestQualifier fun provideJavaDataB() = TestDataB("test")
 
-  @Provides
-  @JavaTestQualifierWithTarget
-  fun provideJavaWithTargetDataA() = TestDataA("test")
+  @Provides @JavaTestQualifierWithTarget fun provideJavaWithTargetDataA() = TestDataA("test")
 
-  @Provides
-  @KotlinTestQualifier
-  fun provideKotlinDataA() = TestDataA("test")
+  @Provides @KotlinTestQualifier fun provideKotlinDataA() = TestDataA("test")
 
-  @Provides
-  @JavaTestQualifier
-  fun provideString() = "qualified string"
+  @Provides @JavaTestQualifier fun provideString() = "qualified string"
 }
 
-class TestConstructionInjectedClassWithQualifier @Inject constructor(
-  @JavaTestQualifier val data: TestDataA
-)
+class TestConstructionInjectedClassWithQualifier
+@Inject
+constructor(@JavaTestQualifier val data: TestDataA)
 
 @TriggerGeneratedTypeProcessor
 class TestMemberInjectedClassWithQualifier {
-  @Inject
-  @JavaTestQualifier
-  lateinit var javaDataA: TestDataA
+  @Inject @JavaTestQualifier lateinit var javaDataA: TestDataA
 
-  @Inject
-  @field:JavaTestQualifier
-  lateinit var javaDataB: TestDataB
+  @Inject @field:JavaTestQualifier lateinit var javaDataB: TestDataB
 
-  @Inject
-  @JavaTestQualifierWithTarget
-  lateinit var javaWithTargetDataA: TestDataA
+  @Inject @JavaTestQualifierWithTarget lateinit var javaWithTargetDataA: TestDataA
 
-  @Inject
-  @JavaTestQualifier
-  lateinit var kotlinDataA: TestDataA
+  @Inject @KotlinTestQualifier lateinit var kotlinDataA: TestDataA
 
-  @Inject
-  lateinit var dataWithConstructionInjection: TestConstructionInjectedClassWithQualifier
+  @set:Inject @setparam:KotlinTestQualifier var kotlinDataA2: TestDataA? = null
+
+  @Inject lateinit var dataWithConstructionInjection: TestConstructionInjectedClassWithQualifier
 
   val noBackingFieldProperty: Int
     get() = 0
@@ -88,8 +72,14 @@
 }
 
 data class TestDataA(val data: String)
+
 data class TestDataB(val data: String)
 
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-annotation class KotlinTestQualifier
+@Target(
+  AnnotationTarget.FUNCTION,
+  AnnotationTarget.PROPERTY,
+  AnnotationTarget.VALUE_PARAMETER,
+  AnnotationTarget.FIELD,
+  AnnotationTarget.PROPERTY_SETTER,
+)
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class KotlinTestQualifier
diff --git a/javatests/dagger/functional/kotlin/PropertyQualifierTest.java b/javatests/dagger/functional/kotlin/PropertyQualifierTest.java
index e0ebf3c..9d2de4a 100644
--- a/javatests/dagger/functional/kotlin/PropertyQualifierTest.java
+++ b/javatests/dagger/functional/kotlin/PropertyQualifierTest.java
@@ -34,6 +34,7 @@
     assertThat(injectedClass.javaDataB).isNotNull();
     assertThat(injectedClass.javaWithTargetDataA).isNotNull();
     assertThat(injectedClass.kotlinDataA).isNotNull();
+    assertThat(injectedClass.getKotlinDataA2()).isNotNull();
     assertThat(injectedClass.dataWithConstructionInjection).isNotNull();
     assertThat(injectedClass.dataWithConstructionInjection.getData()).isNotNull();
   }
diff --git a/javatests/dagger/functional/kotlin/processor/BUILD b/javatests/dagger/functional/kotlin/processor/BUILD
index 25273e2..ec147bc 100644
--- a/javatests/dagger/functional/kotlin/processor/BUILD
+++ b/javatests/dagger/functional/kotlin/processor/BUILD
@@ -11,7 +11,8 @@
 # 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.
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_plugin")
 
 package(default_visibility = ["//:src"])
 
diff --git a/javatests/dagger/functional/kotlinsrc/assisted/kotlin/KotlinAssistedInjectionTest.kt b/javatests/dagger/functional/kotlinsrc/assisted/kotlin/KotlinAssistedInjectionTest.kt
index b58d930..ebe8dcb 100644
--- a/javatests/dagger/functional/kotlinsrc/assisted/kotlin/KotlinAssistedInjectionTest.kt
+++ b/javatests/dagger/functional/kotlinsrc/assisted/kotlin/KotlinAssistedInjectionTest.kt
@@ -28,8 +28,11 @@
   @Component
   internal interface TestComponent {
     fun fooFactory(): FooFactory
+
     fun fooDataFactory(): FooDataFactory
+
     fun barManagerFactory(): BarManager.Factory
+
   }
 
   @Test
diff --git a/javatests/dagger/functional/kotlinsrc/multibindings/BUILD b/javatests/dagger/functional/kotlinsrc/multibindings/BUILD
index 40c2329..64e5dfb 100644
--- a/javatests/dagger/functional/kotlinsrc/multibindings/BUILD
+++ b/javatests/dagger/functional/kotlinsrc/multibindings/BUILD
@@ -25,10 +25,24 @@
 package(default_visibility = ["//:src"])
 
 GenKtTests(
-    name = "multibindings",
-    srcs = glob(["*.kt"]),
+    name = "MultibindingTest",
+    srcs = [
+        "BooleanKey.kt",
+        "ByteKey.kt",
+        "CharKey.kt",
+        "MultibindingComponent.kt",
+        "MultibindingDependency.kt",
+        "MultibindingModule.kt",
+        "MultibindingTest.kt",
+        "MultibindsModule.kt",
+        "NestedAnnotationContainer.kt",
+        "NumberClassKey.kt",
+        "ShortKey.kt",
+        "UnwrappedAnnotationKey.kt",
+        "WrappedAnnotationKey.kt",
+    ],
     gen_library_deps = [
-        "//javatests/dagger/functional/kotlinsrc/multibindings/subpackage",
+        "//javatests/dagger/functional/kotlinsrc/multibindings/subpackage:ContributionsModule",
     ],
     javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
     deps = [
@@ -38,3 +52,66 @@
         "//third_party/java/truth",
     ],
 )
+
+GenKtTests(
+    name = "BindsInaccessibleMapKeyTest",
+    srcs = ["BindsInaccessibleMapKeyTest.kt"],
+    gen_library_deps = [
+        "//javatests/dagger/functional/kotlinsrc/multibindings/subpackage:BindsInaccessibleMapKeyModule",
+    ],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenKtTests(
+    name = "ClassKeyWithGenericsTest",
+    srcs = ["ClassKeyWithGenericsTest.kt"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenKtTests(
+    name = "ComplexMapKeysInDifferentOrderTest",
+    srcs = ["ComplexMapKeysInDifferentOrderTest.kt"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/auto:value",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenKtTests(
+    name = "MapKeyWithDefaultTest",
+    srcs = ["MapKeyWithDefaultTest.kt"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/auto:value",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenKtTests(
+    name = "LazyMapsTest",
+    srcs = [
+        "LazyMaps.kt",
+        "LazyMapsTest.kt",
+    ],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
diff --git a/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKey.kt b/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKey.kt
deleted file mode 100644
index 1b60250..0000000
--- a/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKey.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2023 The Dagger 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
- *
- * 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 dagger.functional.kotlinsrc.multibindings
-
-import dagger.Component
-import dagger.functional.kotlinsrc.multibindings.subpackage.BindsInaccessibleMapKeyModule
-
-// b/73820357
-@Component(modules = [BindsInaccessibleMapKeyModule::class])
-internal interface BindsInaccessibleMapKey {
-  fun mapWithAnInaccessibleMapKey(): Map<Class<*>, Any>
-}
diff --git a/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKeyTest.kt b/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKeyTest.kt
new file mode 100644
index 0000000..6076e23
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/multibindings/BindsInaccessibleMapKeyTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.functional.kotlinsrc.multibindings
+
+import com.google.common.truth.Truth.assertThat
+import dagger.Component
+import dagger.functional.kotlinsrc.multibindings.subpackage.BindsInaccessibleMapKeyModule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+// b/73820357
+@RunWith(JUnit4::class)
+class BindsInaccessibleMapKeyTest {
+  @Component(modules = [BindsInaccessibleMapKeyModule::class])
+  internal interface TestComponent {
+    fun mapWithAnInaccessibleMapKey(): Map<Class<*>, Any>
+  }
+
+  @Test
+  fun test() {
+    val map = DaggerBindsInaccessibleMapKeyTest_TestComponent.create().mapWithAnInaccessibleMapKey()
+    assertThat(map).hasSize(1)
+    assertThat(map.keys.single().canonicalName)
+        .isEqualTo("dagger.functional.kotlinsrc.multibindings.subpackage.Inaccessible");
+  }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/multibindings/subpackage/BUILD b/javatests/dagger/functional/kotlinsrc/multibindings/subpackage/BUILD
index d85fe39..3442486 100644
--- a/javatests/dagger/functional/kotlinsrc/multibindings/subpackage/BUILD
+++ b/javatests/dagger/functional/kotlinsrc/multibindings/subpackage/BUILD
@@ -25,8 +25,17 @@
 package(default_visibility = ["//:src"])
 
 GenKtLibrary(
-    name = "subpackage",
-    srcs = glob(["*.kt"]),
+    name = "ContributionsModule",
+    srcs = ["ContributionsModule.kt"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+    ],
+)
+
+GenKtLibrary(
+    name = "BindsInaccessibleMapKeyModule",
+    srcs = ["BindsInaccessibleMapKeyModule.kt"],
     javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
     deps = [
         "//:dagger_with_compiler",
diff --git a/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
index c790a66..71d08e3 100644
--- a/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
+++ b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
@@ -21,9 +21,11 @@
 import dagger.Module
 import dagger.Provides
 import dagger.Reusable
+import dagger.multibindings.IntoSet
 import java.lang.NullPointerException
 import javax.inject.Inject
 import javax.inject.Provider
+import javax.inject.Singleton
 import org.junit.Assert.fail
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -34,19 +36,37 @@
   @Component(dependencies = [NullComponent::class])
   internal interface NullComponentWithDependency {
     fun string(): String?
+
     fun number(): Number
+
     fun stringProvider(): Provider<String>
+
     fun numberProvider(): Provider<Number>
   }
 
+  interface Bar<T> {}
+
+  class BarNoNull : Bar<String>
+
+  class BarWithNull : Bar<String?>
+
   @Component(modules = [NullModule::class])
   internal interface NullComponent {
     fun string(): String?
+
     fun integer(): Int?
+
     fun nullFoo(): NullFoo
+
     fun number(): Number
+
     fun stringProvider(): Provider<String>
+
     fun numberProvider(): Provider<Number>
+
+    fun setOfBar(): Set<Bar<String>>
+
+    fun setOfBarWithNullableArg(): Set<Bar<String?>>
   }
 
   @Module
@@ -54,6 +74,10 @@
     var numberValue: Number? = null
     var integerCallCount = 0
 
+    @IntoSet @Provides fun providesNullableStringInToSet(): Bar<String?> = BarWithNull()
+
+    @IntoSet @Provides fun providesNonNullStringIntoSet(): Bar<String> = BarNoNull()
+
     @Provides fun provideNullableString(): String? = null
 
     @Provides fun provideNumber(): Number = numberValue!!
@@ -73,7 +97,7 @@
     val string: String?,
     val number: Number,
     val stringProvider: Provider<String>,
-    val numberProvider: Provider<Number>
+    val numberProvider: Provider<Number>,
   ) {
     var methodInjectedString: String? = null
     lateinit var methodInjectedNumber: Number
@@ -85,7 +109,7 @@
       string: String?,
       number: Number,
       stringProvider: Provider<String>,
-      numberProvider: Provider<Number>
+      numberProvider: Provider<Number>,
     ) {
       methodInjectedString = string
       methodInjectedNumber = number
@@ -126,12 +150,12 @@
     validate(
       nullFoo.methodInjectedString,
       nullFoo.methodInjectedStringProvider,
-      nullFoo.methodInjectedNumberProvider
+      nullFoo.methodInjectedNumberProvider,
     )
     validate(
       nullFoo.fieldInjectedString,
       nullFoo.fieldInjectedStringProvider,
-      nullFoo.fieldInjectedNumberProvider
+      nullFoo.fieldInjectedNumberProvider,
     )
   }
 
@@ -146,6 +170,8 @@
     assertThat(module.integerCallCount).isEqualTo(1)
     assertThat(component.integer()).isNull()
     assertThat(module.integerCallCount).isEqualTo(1)
+    assertThat(component.setOfBar().size).isEqualTo(2)
+    assertThat(component.setOfBarWithNullableArg().size).isEqualTo(2)
   }
 
   @Test
@@ -153,11 +179,20 @@
     val nullComponent: NullComponent =
       object : NullComponent {
         override fun string(): String? = null
+
         override fun integer(): Int? = null
+
         override fun stringProvider(): Provider<String> = Provider { null!! }
+
         override fun numberProvider(): Provider<Number> = Provider { null!! }
+
         override fun number(): Number = null!!
+
         override fun nullFoo(): NullFoo = null!!
+
+        override fun setOfBar(): Set<Bar<String>> = emptySet()
+
+        override fun setOfBarWithNullableArg(): Set<Bar<String?>> = emptySet()
       }
     val component =
       DaggerNullabilityTest_NullComponentWithDependency.builder()
@@ -181,7 +216,7 @@
   private fun validate(
     string: String?,
     stringProvider: Provider<String>,
-    numberProvider: Provider<Number>
+    numberProvider: Provider<Number>,
   ) {
     assertThat(string).isNull()
     assertThat(numberProvider).isNotNull()
diff --git a/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java b/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java
index 7cd97d9..729059a 100644
--- a/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java
+++ b/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import dagger.BindsInstance;
 import dagger.Component;
 import dagger.Module;
 import dagger.Provides;
@@ -36,6 +37,16 @@
     @Inject Foo() {}
   }
 
+  static final class Bar {
+    // Checks that member injection fields can use injecting a bound instance that was
+    // named "instance" when bound. Note that the field name here doesn't matter as of
+    // this writing, but name it "instance" anyway in case that changes.
+    // https://github.com/google/dagger/issues/4352
+    @Inject BoundInstance instance;
+
+    @Inject Bar() {}
+  }
+
   @Module
   interface TestModule {
     @Provides
@@ -44,16 +55,60 @@
     }
   }
 
+  public static final class BoundInstance {}
+
   @Component(modules = TestModule.class)
   interface TestComponent {
     Foo foo();
+
+    Bar bar();
+
+    @Component.Builder
+    interface Builder {
+      // As of writing, the method name is the one that matters, but name the
+      // parameter the same anyway in case that changes.
+      Builder instance(@BindsInstance BoundInstance instance);
+      TestComponent build();
+    }
+  }
+
+  @Component(modules = TestModule.class)
+  interface TestComponentWithFactory {
+    Foo foo();
+
+    Bar bar();
+
+    @Component.Factory
+    interface Factory {
+      // As of writing, the parameter name is the one that matters, but name the
+      // method the same anyway in case that changes.
+      TestComponentWithFactory instance(@BindsInstance BoundInstance instance);
+    }
   }
 
   @Test
   public void testMemberWithInstanceName() {
-    TestComponent component = DaggerMembersWithInstanceNameTest_TestComponent.create();
+    BoundInstance boundInstance = new BoundInstance();
+    TestComponent component = DaggerMembersWithInstanceNameTest_TestComponent
+        .builder().instance(boundInstance).build();
     Foo foo = component.foo();
     assertThat(foo).isNotNull();
     assertThat(foo.instance).isEqualTo("test");
+    Bar bar = component.bar();
+    assertThat(bar).isNotNull();
+    assertThat(bar.instance).isSameInstanceAs(boundInstance);
+  }
+
+  @Test
+  public void testMemberWithInstanceNameUsingFactory() {
+    BoundInstance boundInstance = new BoundInstance();
+    TestComponentWithFactory component = DaggerMembersWithInstanceNameTest_TestComponentWithFactory
+        .factory().instance(boundInstance);
+    Foo foo = component.foo();
+    assertThat(foo).isNotNull();
+    assertThat(foo.instance).isEqualTo("test");
+    Bar bar = component.bar();
+    assertThat(bar).isNotNull();
+    assertThat(bar.instance).isSameInstanceAs(boundInstance);
   }
 }
diff --git a/javatests/dagger/functional/multibindings/BUILD b/javatests/dagger/functional/multibindings/BUILD
index 63a7bfd..42153c4 100644
--- a/javatests/dagger/functional/multibindings/BUILD
+++ b/javatests/dagger/functional/multibindings/BUILD
@@ -25,17 +25,106 @@
 package(default_visibility = ["//:src"])
 
 GenJavaTests(
-    name = "multibindings",
-    srcs = glob(["*.java"]),
+    name = "MultibindingTest",
+    srcs = [
+        "BooleanKey.java",
+        "ByteKey.java",
+        "CharKey.java",
+        "MultibindingComponent.java",
+        "MultibindingDependency.java",
+        "MultibindingModule.java",
+        "MultibindingTest.java",
+        "MultibindsModule.java",
+        "NestedAnnotationContainer.java",
+        "NumberClassKey.java",
+        "RequiresFieldInjection.java",
+        "ShortKey.java",
+        "UnwrappedAnnotationKey.java",
+        "WrappedAnnotationKey.java",
+    ],
     gen_library_deps = [
-        "//javatests/dagger/functional/multibindings/subpackage",
+        "//javatests/dagger/functional/multibindings/subpackage:ContributionsModule",
     ],
     javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
     deps = [
         "//:dagger_with_compiler",
         "//third_party/java/auto:value",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenJavaTests(
+    name = "BindsInaccessibleMapKeyTest",
+    srcs = ["BindsInaccessibleMapKeyTest.java"],
+    gen_library_deps = [
+        "//javatests/dagger/functional/multibindings/subpackage:BindsInaccessibleMapKeyModule",
+    ],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
         "//third_party/java/guava/collect",
         "//third_party/java/junit",
         "//third_party/java/truth",
     ],
 )
+
+GenJavaTests(
+    name = "ClassKeyWithGenericsTest",
+    srcs = ["ClassKeyWithGenericsTest.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenJavaTests(
+    name = "LazyClassKeyWithGenericsTest",
+    srcs = ["LazyClassKeyWithGenericsTest.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenJavaTests(
+    name = "ComplexMapKeysInDifferentOrderTest",
+    srcs = ["ComplexMapKeysInDifferentOrderTest.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/auto:value",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenJavaTests(
+    name = "MapKeyWithDefaultTest",
+    srcs = ["MapKeyWithDefaultTest.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/auto:value",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
+
+GenJavaTests(
+    name = "LazyMapsTest",
+    srcs = [
+        "LazyMaps.java",
+        "LazyMapsTest.java",
+    ],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+        "//third_party/java/junit",
+        "//third_party/java/truth",
+    ],
+)
diff --git a/javatests/dagger/functional/multibindings/BindsInaccessibleMapKeyTest.java b/javatests/dagger/functional/multibindings/BindsInaccessibleMapKeyTest.java
new file mode 100644
index 0000000..470f644
--- /dev/null
+++ b/javatests/dagger/functional/multibindings/BindsInaccessibleMapKeyTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Dagger 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
+ *
+ * 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 dagger.functional.multibindings;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import dagger.functional.multibindings.subpackage.BindsInaccessibleMapKeyModule;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+// b/73820357
+@RunWith(JUnit4.class)
+public class BindsInaccessibleMapKeyTest {
+  @Component(modules = BindsInaccessibleMapKeyModule.class)
+  interface TestComponent {
+    Map<Class<?>, Object> mapWithAnInaccessibleMapKey();
+  }
+
+  @Test
+  public void test() {
+    Map<Class<?>, Object> map =
+        DaggerBindsInaccessibleMapKeyTest_TestComponent.create().mapWithAnInaccessibleMapKey();
+    assertThat(map).hasSize(1);
+    assertThat(getOnlyElement(map.keySet()).getCanonicalName())
+        .isEqualTo(
+            "dagger.functional.multibindings.subpackage."
+                + "BindsInaccessibleMapKeyModule.Inaccessible");
+  }
+}
diff --git a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java b/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
index 801d120..6883225 100644
--- a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
+++ b/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
@@ -38,13 +38,23 @@
   @interface ComplexMapKey {
     int i();
     int j();
+
+    NestKey[] nestKeys() default {};
+  }
+
+  @Retention(RUNTIME)
+  @MapKey(unwrapValue = false)
+  @interface NestKey {
+    int i() default 0;
+
+    String j() default "";
   }
 
   @Module
   interface TestModule {
     @Provides
     @IntoMap
-    @ComplexMapKey(i = 1, j = 2)
+    @ComplexMapKey(i = 1, j = 2, nestKeys = @NestKey)
     static int inOrder() {
       return 3;
     }
@@ -66,12 +76,21 @@
   public void test() {
     Map<ComplexMapKey, Integer> map =
         DaggerComplexMapKeysInDifferentOrderTest_TestComponent.create().map();
-    assertThat(map.get(mapKey(1, 2))).isEqualTo(3);
-    assertThat(map.get(mapKey(5, 4))).isEqualTo(6);
+    assertThat(map)
+        .containsEntry(
+            mapKey(
+                1,
+                2,
+                new NestKey[] {
+                  new AutoAnnotation_ComplexMapKeysInDifferentOrderTest_ComplexMapKeyCreator_createNestKey(
+                      0, "")
+                }),
+            3);
+    assertThat(map).containsEntry(mapKey(5, 4, new NestKey[] {}), 6);
   }
 
   @AutoAnnotation
-  static ComplexMapKey mapKey(int i, int j) {
-    return new AutoAnnotation_ComplexMapKeysInDifferentOrderTest_mapKey(i, j);
+  static ComplexMapKey mapKey(int i, int j, NestKey[] nestKeys) {
+    return new AutoAnnotation_ComplexMapKeysInDifferentOrderTest_mapKey(i, j, nestKeys);
   }
 }
diff --git a/javatests/dagger/functional/multibindings/LazyClassKeyWithGenericsTest.java b/javatests/dagger/functional/multibindings/LazyClassKeyWithGenericsTest.java
new file mode 100644
index 0000000..95c36f8
--- /dev/null
+++ b/javatests/dagger/functional/multibindings/LazyClassKeyWithGenericsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.functional.multibindings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.LazyClassKey;
+import java.util.Map;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class LazyClassKeyWithGenericsTest {
+  @Component(modules = TestModule.class)
+  @Singleton
+  interface TestComponent {
+    Map<Class<?>, String> map();
+
+    Provider<Map<Class<?>, Provider<Integer>>> intMap();
+  }
+
+  @Module
+  interface TestModule {
+    @Provides
+    @IntoMap
+    @LazyClassKey(Thing.class)
+    static String provideThingValue() {
+      return "Thing";
+    }
+
+    @Provides
+    @IntoMap
+    @LazyClassKey(GenericThing.class)
+    static String provideGenericThingValue() {
+      return "GenericThing";
+    }
+
+    @Provides
+    @IntoMap
+    @LazyClassKey(Thing.class)
+    static Integer provideThingIntValue() {
+      return 2;
+    }
+
+    @Provides
+    @IntoMap
+    @LazyClassKey(GenericThing.class)
+    static Integer provideGenericThingIntValue() {
+      return 1;
+    }
+  }
+
+  class Thing {}
+
+  class GenericThing<T> {}
+
+  @Test
+  public void test() {
+    TestComponent testComponent = DaggerLazyClassKeyWithGenericsTest_TestComponent.create();
+    Map<Class<?>, String> map = testComponent.map();
+    Map<Class<?>, Provider<Integer>> intMap = testComponent.intMap().get();
+    // MapSubject#containsExactly uses entrySet, which is banned from DaggerClassKey map.
+    assertThat(map.get(Thing.class)).isEqualTo("Thing");
+    assertThat(map.get(GenericThing.class)).isEqualTo("GenericThing");
+    assertThat(intMap.get(Thing.class).get()).isEqualTo(2);
+    assertThat(intMap.get(GenericThing.class).get()).isEqualTo(1);
+  }
+}
diff --git a/javatests/dagger/functional/multibindings/MultibindingComponent.java b/javatests/dagger/functional/multibindings/MultibindingComponent.java
index 8e61ae0..77eeb53 100644
--- a/javatests/dagger/functional/multibindings/MultibindingComponent.java
+++ b/javatests/dagger/functional/multibindings/MultibindingComponent.java
@@ -17,6 +17,7 @@
 package dagger.functional.multibindings;
 
 import dagger.Component;
+import dagger.MembersInjector;
 import dagger.functional.multibindings.subpackage.ContributionsModule;
 import dagger.multibindings.StringKey;
 import java.util.Collection;
@@ -67,4 +68,8 @@
 
   @Named("complexQualifier")
   Map<String, CharSequence> maybeEmptyQualifiedMap();
+
+  Map<Class<?>, MembersInjector<?>> membersInjectorMap();
+
+  Set<MembersInjector<?>> membersInjectorSet();
 }
diff --git a/javatests/dagger/functional/multibindings/MultibindingModule.java b/javatests/dagger/functional/multibindings/MultibindingModule.java
index cc34e24..af90d3c 100644
--- a/javatests/dagger/functional/multibindings/MultibindingModule.java
+++ b/javatests/dagger/functional/multibindings/MultibindingModule.java
@@ -16,6 +16,7 @@
 
 package dagger.functional.multibindings;
 
+import dagger.MembersInjector;
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.ClassKey;
@@ -96,6 +97,27 @@
   }
 
   @Provides
+  @Named("fieldInjectedValue")
+  static String provideFieldInjectedValue() {
+    return "fieldInjectedValue";
+  }
+
+  @Provides
+  @IntoMap
+  @ClassKey(RequiresFieldInjection.class)
+  static MembersInjector<?> provideMembersInjectorIntoMap(
+      MembersInjector<RequiresFieldInjection> injector) {
+    return injector;
+  }
+
+  @Provides
+  @IntoSet
+  static MembersInjector<?> provideMembersInjectorIntoSet(
+      MembersInjector<RequiresFieldInjection> injector) {
+    return injector;
+  }
+
+  @Provides
   @IntoMap
   @NestedAnnotationContainer.NestedWrappedKey(Integer.class)
   static String valueForInteger() {
diff --git a/javatests/dagger/functional/multibindings/MultibindingTest.java b/javatests/dagger/functional/multibindings/MultibindingTest.java
index 9787764..96037fe 100644
--- a/javatests/dagger/functional/multibindings/MultibindingTest.java
+++ b/javatests/dagger/functional/multibindings/MultibindingTest.java
@@ -19,11 +19,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.auto.value.AutoAnnotation;
+import dagger.MembersInjector;
 import dagger.multibindings.ClassKey;
 import dagger.multibindings.StringKey;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Map;
+import java.util.Set;
 import javax.inject.Provider;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -183,6 +185,29 @@
         .containsEntry("key", "qualified foo value");
   }
 
+  @SuppressWarnings("unchecked")  // We know the single type in the set
+  @Test
+  public void membersInjectorSet() {
+    Set<MembersInjector<?>> injectors = multibindingComponent.membersInjectorSet();
+    assertThat(injectors).hasSize(1);
+    RequiresFieldInjection injected = new RequiresFieldInjection();
+    assertThat(injected.value).isNull();
+    ((MembersInjector<RequiresFieldInjection>) injectors.iterator().next()).injectMembers(injected);
+    assertThat(injected.value).isEqualTo("fieldInjectedValue");
+  }
+
+  @SuppressWarnings("unchecked")  // We know the single type in the map
+  @Test
+  public void membersInjectorMap() {
+    Map<Class<?>, MembersInjector<?>> injectors = multibindingComponent.membersInjectorMap();
+    assertThat(injectors).hasSize(1);
+    RequiresFieldInjection injected = new RequiresFieldInjection();
+    assertThat(injected.value).isNull();
+    ((MembersInjector<RequiresFieldInjection>) injectors.get(RequiresFieldInjection.class))
+        .injectMembers(injected);
+    assertThat(injected.value).isEqualTo("fieldInjectedValue");
+  }
+
   @AutoAnnotation
   static StringKey testStringKey(String value) {
     return new AutoAnnotation_MultibindingTest_testStringKey(value);
diff --git a/javatests/dagger/functional/multibindings/MultibindsModule.java b/javatests/dagger/functional/multibindings/MultibindsModule.java
index b678c9e..72698eb 100644
--- a/javatests/dagger/functional/multibindings/MultibindsModule.java
+++ b/javatests/dagger/functional/multibindings/MultibindsModule.java
@@ -16,6 +16,7 @@
 
 package dagger.functional.multibindings;
 
+import dagger.MembersInjector;
 import dagger.Module;
 import dagger.multibindings.Multibinds;
 import java.util.Map;
@@ -39,9 +40,15 @@
   abstract Set<CharSequence> set();
 
   @Multibinds
+  abstract Set<MembersInjector<?>> membersInjectorSet();
+
+  @Multibinds
   abstract Map<String, CharSequence> map();
 
   @Multibinds
+  abstract Map<Class<?>, MembersInjector<?>> membersInjectorMap();
+
+  @Multibinds
   @Named("complexQualifier")
   abstract Set<Object> emptyQualifiedSet();
 
diff --git a/javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.java b/javatests/dagger/functional/multibindings/RequiresFieldInjection.java
similarity index 64%
rename from javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.java
rename to javatests/dagger/functional/multibindings/RequiresFieldInjection.java
index 6256812..2a1a060 100644
--- a/javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.java
+++ b/javatests/dagger/functional/multibindings/RequiresFieldInjection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Dagger Authors.
+ * Copyright (C) 2024 The Dagger Authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,12 +16,9 @@
 
 package dagger.functional.multibindings;
 
-import dagger.Component;
-import dagger.functional.multibindings.subpackage.BindsInaccessibleMapKeyModule;
-import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Named;
 
-// b/73820357
-@Component(modules = BindsInaccessibleMapKeyModule.class)
-interface BindsInaccessibleMapKey {
-  Map<Class<?>, Object> mapWithAnInaccessibleMapKey();
+public final class RequiresFieldInjection {
+  @Inject @Named("fieldInjectedValue") String value;
 }
diff --git a/javatests/dagger/functional/multibindings/subpackage/BUILD b/javatests/dagger/functional/multibindings/subpackage/BUILD
index fe3abef..1485b04 100644
--- a/javatests/dagger/functional/multibindings/subpackage/BUILD
+++ b/javatests/dagger/functional/multibindings/subpackage/BUILD
@@ -25,8 +25,17 @@
 package(default_visibility = ["//:src"])
 
 GenJavaLibrary(
-    name = "subpackage",
-    srcs = glob(["*.java"]),
+    name = "ContributionsModule",
+    srcs = ["ContributionsModule.java"],
+    javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+    deps = [
+        "//:dagger_with_compiler",
+    ],
+)
+
+GenJavaLibrary(
+    name = "BindsInaccessibleMapKeyModule",
+    srcs = ["BindsInaccessibleMapKeyModule.java"],
     javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
     deps = [
         "//:dagger_with_compiler",
diff --git a/javatests/dagger/functional/producers/binds/SimpleBindingModule.java b/javatests/dagger/functional/producers/binds/SimpleBindingModule.java
index f2af277..4eaec46 100644
--- a/javatests/dagger/functional/producers/binds/SimpleBindingModule.java
+++ b/javatests/dagger/functional/producers/binds/SimpleBindingModule.java
@@ -37,7 +37,6 @@
 import java.util.concurrent.Executor;
 import javax.inject.Named;
 import javax.inject.Qualifier;
-import javax.inject.Singleton;
 
 @ProducerModule(includes = {
     SimpleBindingModule.ExecutorModule.class,
@@ -54,7 +53,6 @@
   abstract Foo<? extends Number> bindFooOfNumbers(Foo<Integer> fooOfIntegers);
 
   @Binds
-  @Singleton
   @SomeQualifier
   abstract Foo<String> bindQualifiedFooOfStrings(FooOfStrings impl);
 
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java b/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
index 651bdf8..69c53b8 100644
--- a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
+++ b/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
@@ -29,7 +29,6 @@
 import java.util.Map;
 import java.util.Set;
 
-
 @ProductionComponent(
   modules = {ExecutorModule.class, MultibindingProducerModule.class, MultibindingModule.class}
 )
@@ -48,6 +47,12 @@
 
   ListenableFuture<Map<Integer, Produced<String>>> mapOfProduced();
 
+  ListenableFuture<Map<Class<?>, Produced<String>>> lazyClassKeyMapOfProduced();
+
+  ListenableFuture<Map<Class<?>, String>> lazyClassKeyMapOfString();
+
+  ListenableFuture<Map<Class<?>, Producer<String>>> lazyClassKeyMapOfProducer();
+
   @PossiblyThrowingMap
   ListenableFuture<Map<Integer, String>> possiblyThrowingMap();
 
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java b/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java
index 350733b..b04ae7e 100644
--- a/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java
+++ b/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java
@@ -27,6 +27,7 @@
 import dagger.multibindings.IntKey;
 import dagger.multibindings.IntoMap;
 import dagger.multibindings.IntoSet;
+import dagger.multibindings.LazyClassKey;
 import dagger.multibindings.Multibinds;
 import dagger.producers.Produced;
 import dagger.producers.ProducerModule;
@@ -36,6 +37,8 @@
 
 @ProducerModule
 abstract class MultibindingProducerModule {
+  static class Foo {}
+
   @Produces
   @IntoSet
   static ListenableFuture<String> futureStr() {
@@ -122,6 +125,13 @@
     throw new RuntimeException("monkey");
   }
 
+  @Produces
+  @IntoMap
+  @LazyClassKey(Foo.class)
+  static String produceName() {
+    return "foo";
+  }
+
   @Multibinds
   abstract Set<Object> objs();
 
diff --git a/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java b/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java
index f7059c7..1e3a46d 100644
--- a/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java
+++ b/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java
@@ -25,6 +25,8 @@
 import dagger.producers.Production;
 import dagger.producers.ProductionComponent;
 import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicInteger;
 import javax.inject.Inject;
@@ -32,12 +34,15 @@
 import javax.inject.Qualifier;
 
 final class SubcomponentsWithBoundExecutor {
+  @Retention(RetentionPolicy.RUNTIME)  // Technically a JSR330 requirement
   @Qualifier
   @interface FromParent {}
 
+  @Retention(RetentionPolicy.RUNTIME)  // Technically a JSR330 requirement
   @Qualifier
   @interface FromChild {}
 
+  @Retention(RetentionPolicy.RUNTIME)  // Technically a JSR330 requirement
   @Qualifier
   @interface FromGrandchild {}
 
diff --git a/javatests/dagger/hilt/android/AndroidManifest.xml b/javatests/dagger/hilt/android/AndroidManifest.xml
index ed24e45..24efa4d 100644
--- a/javatests/dagger/hilt/android/AndroidManifest.xml
+++ b/javatests/dagger/hilt/android/AndroidManifest.xml
@@ -46,6 +46,10 @@
         android:exported="false"
         tools:ignore="MissingClass"/>
     <activity
+        android:name=".PackagePrivateConstructorTest$TestActivity"
+        android:exported="false"
+        tools:ignore="MissingClass"/>
+    <activity
         android:name=".QualifierInKotlinFieldsTest$TestActivity"
         android:exported="false"
         tools:ignore="MissingClass"/>
diff --git a/javatests/dagger/hilt/android/BUILD b/javatests/dagger/hilt/android/BUILD
index b3da0d2..f3ae20f 100644
--- a/javatests/dagger/hilt/android/BUILD
+++ b/javatests/dagger/hilt/android/BUILD
@@ -360,6 +360,22 @@
 )
 
 android_local_test(
+    name = "PackagePrivateConstructorTest",
+    srcs = ["PackagePrivateConstructorTest.java"],
+    manifest = "AndroidManifest.xml",
+    manifest_values = {
+        "minSdkVersion": "14",
+    },
+    deps = [
+        "//:android_local_test_exports",
+        "//java/dagger/hilt/android:android_entry_point",
+        "//java/dagger/hilt/android:package_info",
+        "//java/dagger/hilt/android/testing:hilt_android_test",
+        "//javatests/dagger/hilt/android/testsubpackage:PackagePrivateConstructorTestClasses",
+    ],
+)
+
+android_local_test(
     name = "QualifierInKotlinFieldsTest",
     srcs = ["QualifierInKotlinFieldsTest.java"],
     manifest = "AndroidManifest.xml",
diff --git a/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt b/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt
index fb4afc0..c741a35 100644
--- a/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt
+++ b/javatests/dagger/hilt/android/EntryPointAccessorsTest.kt
@@ -27,14 +27,18 @@
 import dagger.Module
 import dagger.Provides
 import dagger.hilt.EntryPoint
+import dagger.hilt.EntryPoints
 import dagger.hilt.InstallIn
 import dagger.hilt.android.components.ActivityComponent
 import dagger.hilt.android.components.FragmentComponent
+import dagger.hilt.android.components.FragmentRetainedComponent
 import dagger.hilt.android.components.ViewComponent
+import dagger.hilt.android.internal.managers.InternalFragmentRetainedComponent
 import dagger.hilt.android.testing.HiltAndroidRule
 import dagger.hilt.android.testing.HiltAndroidTest
 import dagger.hilt.android.testing.HiltTestApplication
 import dagger.hilt.components.SingletonComponent
+import javax.inject.Inject
 import javax.inject.Qualifier
 import org.junit.Rule
 import org.junit.Test
@@ -55,24 +59,15 @@
     const val VIEW_STRING = "VIEW_STRING"
   }
 
-  @get:Rule
-  var rule = HiltAndroidRule(this)
+  @get:Rule var rule = HiltAndroidRule(this)
 
-  @Qualifier
-  @Retention(AnnotationRetention.BINARY)
-  annotation class ApplicationLevel
+  @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ApplicationLevel
 
-  @Qualifier
-  @Retention(AnnotationRetention.BINARY)
-  annotation class ActivityLevel
+  @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ActivityLevel
 
-  @Qualifier
-  @Retention(AnnotationRetention.BINARY)
-  annotation class FragmentLevel
+  @Qualifier @Retention(AnnotationRetention.BINARY) annotation class FragmentLevel
 
-  @Qualifier
-  @Retention(AnnotationRetention.BINARY)
-  annotation class ViewLevel
+  @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ViewLevel
 
   @Module
   @InstallIn(SingletonComponent::class)
@@ -117,50 +112,43 @@
   @EntryPoint
   @InstallIn(SingletonComponent::class)
   internal interface ApplicationEntryPoint {
-    @ApplicationLevel
-    fun getString(): String
+    @ApplicationLevel fun getString(): String
   }
 
   @EntryPoint
   @InstallIn(ActivityComponent::class)
   internal interface ActivityEntryPoint {
-    @ActivityLevel
-    fun getString(): String
+    @ActivityLevel fun getString(): String
   }
 
   @EntryPoint
   @InstallIn(FragmentComponent::class)
   internal interface FragmentEntryPoint {
-    @FragmentLevel
-    fun getString(): String
+    @FragmentLevel fun getString(): String
   }
 
   @EntryPoint
   @InstallIn(ViewComponent::class)
   internal interface ViewEntryPoint {
-    @ViewLevel
-    fun getString(): String
+    @ViewLevel fun getString(): String
   }
 
   @Test
   fun testApplicationEntryPoint() {
     val app = getApplicationContext<HiltTestApplication>()
     val entryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(app)
-    Truth.assertThat(entryPoint.getString())
-      .isEqualTo(APPLICATION_STRING)
+    Truth.assertThat(entryPoint.getString()).isEqualTo(APPLICATION_STRING)
 
     val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
     val applicationEntryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(activity)
-    Truth.assertThat(applicationEntryPoint.getString())
-      .isEqualTo(APPLICATION_STRING)
+    Truth.assertThat(applicationEntryPoint.getString()).isEqualTo(APPLICATION_STRING)
   }
 
   @Test
   fun testActivityEntryPoint() {
     val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
     val entryPoint = EntryPointAccessors.fromActivity<ActivityEntryPoint>(activity)
-    Truth.assertThat(entryPoint.getString())
-      .isEqualTo(ACTIVITY_STRING)
+    Truth.assertThat(entryPoint.getString()).isEqualTo(ACTIVITY_STRING)
   }
 
   @Test
@@ -169,8 +157,7 @@
     val fragment = TestFragment()
     activity.supportFragmentManager.beginTransaction().add(fragment, "").commitNow()
     val entryPoint = EntryPointAccessors.fromFragment<FragmentEntryPoint>(fragment)
-    Truth.assertThat(entryPoint.getString())
-      .isEqualTo(FRAGMENT_STRING)
+    Truth.assertThat(entryPoint.getString()).isEqualTo(FRAGMENT_STRING)
   }
 
   @Test
@@ -178,15 +165,15 @@
     val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get()
     val view = TestView(activity)
     val entryPoint = EntryPointAccessors.fromView<ViewEntryPoint>(view)
-    Truth.assertThat(entryPoint.getString())
-      .isEqualTo(VIEW_STRING)
+    Truth.assertThat(entryPoint.getString()).isEqualTo(VIEW_STRING)
   }
 
   @AndroidEntryPoint(FragmentActivity::class)
   class TestActivity : Hilt_EntryPointAccessorsTest_TestActivity()
 
   @AndroidEntryPoint(Fragment::class)
-  class TestFragment : Hilt_EntryPointAccessorsTest_TestFragment()
+  class TestFragment : Hilt_EntryPointAccessorsTest_TestFragment() {
+  }
 
   @AndroidEntryPoint(View::class)
   class TestView(context: Context) : Hilt_EntryPointAccessorsTest_TestView(context)
diff --git a/javatests/dagger/hilt/android/PackagePrivateConstructorTest.java b/javatests/dagger/hilt/android/PackagePrivateConstructorTest.java
new file mode 100644
index 0000000..d20ff98
--- /dev/null
+++ b/javatests/dagger/hilt/android/PackagePrivateConstructorTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.hilt.android;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import dagger.hilt.android.testing.HiltAndroidRule;
+import dagger.hilt.android.testing.HiltAndroidTest;
+import dagger.hilt.android.testing.HiltTestApplication;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseActivity;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseBroadcastReceiver;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseFragment;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseIntentService;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseService;
+import dagger.hilt.android.testsubpackage.PackagePrivateConstructorTestClasses.BaseView;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+/** Regression test for b/331280240. */
+@HiltAndroidTest
+@RunWith(AndroidJUnit4.class)
+// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
+@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
+public final class PackagePrivateConstructorTest {
+  @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this);
+
+  @AndroidEntryPoint(BaseActivity.class)
+  public static final class TestActivity extends Hilt_PackagePrivateConstructorTest_TestActivity {
+  }
+
+  @AndroidEntryPoint(BaseFragment.class)
+  public static final class TestFragment extends Hilt_PackagePrivateConstructorTest_TestFragment {
+  }
+
+  @AndroidEntryPoint(BaseView.class)
+  public static final class TestView extends Hilt_PackagePrivateConstructorTest_TestView {
+      TestView(Context context) {
+        super(context);
+      }
+  }
+
+  @AndroidEntryPoint(BaseService.class)
+  public static final class TestService extends Hilt_PackagePrivateConstructorTest_TestService {
+    @Override
+    public IBinder onBind(Intent intent) {
+      return null;
+    }
+  }
+
+  @AndroidEntryPoint(BaseIntentService.class)
+  public static final class TestIntentService
+      extends Hilt_PackagePrivateConstructorTest_TestIntentService {
+    public TestIntentService() {
+      super("TestIntentServiceName");
+    }
+
+    @Override
+    public void onHandleIntent(Intent intent) {}
+  }
+
+  @AndroidEntryPoint(BaseBroadcastReceiver.class)
+  public static final class TestBroadcastReceiver
+      extends Hilt_PackagePrivateConstructorTest_TestBroadcastReceiver {
+  }
+
+  @Before
+  public void setup() {
+    rule.inject();
+  }
+
+  // Technically all the tests need to do is check for compilation, but might as well make sure the
+  // classes are usable
+  @Test
+  public void testActivityFragmentView() throws Exception {
+    try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
+      scenario.onActivity(
+          activity -> {
+            TestFragment fragment = new TestFragment();
+            activity.getSupportFragmentManager().beginTransaction().add(fragment, "").commitNow();
+            TestView unused = new TestView(fragment.getContext());
+          });
+    }
+  }
+
+  @Test
+  public void testServices() throws Exception {
+    Robolectric.setupService(TestService.class);
+    Robolectric.setupService(TestIntentService.class);
+  }
+
+  @Test
+  public void testBroadcastReceiver() throws Exception {
+    TestBroadcastReceiver testBroadcastReceiver = new TestBroadcastReceiver();
+    Intent intent = new Intent();
+    testBroadcastReceiver.onReceive(ApplicationProvider.getApplicationContext(), intent);
+  }
+}
diff --git a/javatests/dagger/hilt/android/processor/internal/BUILD b/javatests/dagger/hilt/android/processor/internal/BUILD
index ac89e9d..8bb88bd 100644
--- a/javatests/dagger/hilt/android/processor/internal/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/BUILD
@@ -24,7 +24,7 @@
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android:android_entry_point",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
     ],
     deps = [
diff --git a/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java b/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
index 55e6966..5705c91 100644
--- a/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/GeneratorsTest.java
@@ -123,19 +123,122 @@
                     JOINER.join(
                         "  Hilt_MyView(Context p0, @Nullable AttributeSet p1) {",
                         "    super(p0, p1);",
-                        "    inject();",
+                        "    if(!isInEditMode()) {",
+                        "      inject();",
+                        "    }",
                         "  }"));
               } else {
                 stringSubject.contains(
                     JOINER.join(
                         "  Hilt_MyView(Context context, @Nullable AttributeSet attrs) {",
                         "    super(context, attrs);",
-                        "    inject();",
+                        "    if(!isInEditMode()) {",
+                        "      inject();",
+                        "    }",
                         "  }"));
               }
             });
   }
 
+  // This is a regression test for b/382104423
+  @Test
+  public void typeUseNullableCopiedFromSuperConstructor() {
+    Source baseView =
+        HiltCompilerTests.javaSource(
+            "test.BaseView",
+            "package test;",
+            "",
+            "import android.content.Context;",
+            "import android.util.AttributeSet;",
+            "import android.view.View;",
+            "import org.jspecify.annotations.Nullable;",
+            "",
+            "public class BaseView extends View {",
+            "  public BaseView(Context context, @Nullable AttributeSet attrs) {",
+            "    super(context, attrs);",
+            "  }",
+            "}");
+    Source myView =
+        HiltCompilerTests.javaSource(
+            "test.MyView",
+            "package test;",
+            "",
+            "import android.content.Context;",
+            "import android.util.AttributeSet;",
+            "import android.view.View;",
+            "import dagger.hilt.android.AndroidEntryPoint;",
+            "import org.jspecify.annotations.Nullable;",
+            "",
+            "@AndroidEntryPoint(BaseView.class)",
+            "public class MyView extends Hilt_MyView {",
+            "  public MyView(Context context, @Nullable AttributeSet attrs) {",
+            "    super(context, attrs);",
+            "  }",
+            "}");
+    HiltCompilerTests.hiltCompiler(baseView, myView)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              StringSubject stringSubject =
+                  subject.generatedSourceFileWithPath("test/Hilt_MyView.java");
+              stringSubject.contains("org.jspecify.annotations.Nullable");
+            });
+  }
+
+  @Test
+  public void hybridTypeUseAndDeclarationNullableNotDuplicated() {
+    Source hybridNullable =
+        HiltCompilerTests.javaSource(
+            "test.Nullable",
+            "package test;",
+            "",
+            "import static java.lang.annotation.ElementType.PARAMETER;",
+            "import static java.lang.annotation.ElementType.TYPE_USE;",
+            "",
+            "import java.lang.annotation.Target;",
+            "",
+            "@Target({TYPE_USE, PARAMETER})",
+            "public @interface Nullable {}");
+    Source baseView =
+        HiltCompilerTests.javaSource(
+            "test.BaseView",
+            "package test;",
+            "",
+            "import android.content.Context;",
+            "import android.util.AttributeSet;",
+            "import android.view.View;",
+            "",
+            "public class BaseView extends View {",
+            "  public BaseView(Context context, @Nullable AttributeSet attrs) {",
+            "    super(context, attrs);",
+            "  }",
+            "}");
+    Source myView =
+        HiltCompilerTests.javaSource(
+            "test.MyView",
+            "package test;",
+            "",
+            "import android.content.Context;",
+            "import android.util.AttributeSet;",
+            "import android.view.View;",
+            "import dagger.hilt.android.AndroidEntryPoint;",
+            "",
+            "@AndroidEntryPoint(BaseView.class)",
+            "public class MyView extends Hilt_MyView {",
+            "  public MyView(Context context, @Nullable AttributeSet attrs) {",
+            "    super(context, attrs);",
+            "  }",
+            "}");
+    HiltCompilerTests.hiltCompiler(hybridNullable, baseView, myView)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              StringSubject stringSubject =
+                  subject.generatedSourceFileWithPath("test/Hilt_MyView.java");
+              stringSubject.contains("@Nullable");
+            });
+  }
+
   // This is a regression test for https://github.com/google/dagger/issues/3296
   @Test
   public void isRestrictedApiConstructorWithPrimitiveParameterTest() {
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
index 146f537..2cf63e0 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
@@ -14,6 +14,7 @@
 # Description:
 #   Tests for internal code for implementing Hilt processors.
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
 
 package(default_visibility = ["//:src"])
@@ -30,7 +31,7 @@
         "//java/dagger/hilt/android/internal/modules",
         "//java/dagger/hilt/testing:test_install_in",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
         "//java/dagger/hilt/android/testing/compile",
@@ -49,7 +50,7 @@
         "//java/dagger/hilt/android:early_entry_point",
         "//java/dagger/hilt/android/components",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
         "//java/dagger/hilt/android/testing/compile",
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index 8a39641..33bd535 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -23,7 +23,7 @@
     srcs = ["ActivityGeneratorTest.java"],
     compiler_deps = [
         "//java/dagger/hilt/android:android_entry_point",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     resources = glob([
         "goldens/ActivityGeneratorTest_*",
@@ -42,10 +42,9 @@
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android:android_entry_point",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
-        "//java/dagger/hilt/android:android_entry_point",
         "//java/dagger/hilt/android/testing/compile",
         "//java/dagger/internal/codegen/xprocessing",
         "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
@@ -60,7 +59,7 @@
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android:android_entry_point",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
         "//java/dagger/hilt/android/testing/compile",
diff --git a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index a8d2cb9..47c9688 100644
--- a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -25,7 +25,7 @@
         "//java/dagger/hilt/android/testing:custom_test_application",
         "//java/dagger/hilt/android/testing:hilt_android_test",
         "//java/dagger/hilt/android:hilt_android_app",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
         "//java/dagger/hilt/android/testing/compile",
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
index eb73b3f..129a4fa 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -15,8 +15,8 @@
 # Description:
 #   Tests for internal code for implementing Hilt processors.
 
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 load("//java/dagger/testing/compile:macros.bzl", "kt_compiler_test")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
 
 package(default_visibility = ["//:src"])
 
@@ -25,7 +25,7 @@
     srcs = ["ViewModelProcessorTest.kt"],
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "//java/dagger/hilt/android/lifecycle:hilt_view_model",
     ],
     deps = [
@@ -44,7 +44,7 @@
         "ViewModelValidationPluginTest.kt",
     ],
     compiler_deps = [
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_lifecycle_lifecycle_viewmodel",
         "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
         "//third_party/java/compile_testing",
@@ -76,7 +76,7 @@
         "ViewModelValidationPluginWithAssistedInjectTest.kt",
     ],
     compiler_deps = [
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_lifecycle_lifecycle_viewmodel",
         "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
         "//third_party/java/compile_testing",
diff --git a/javatests/dagger/hilt/android/testsubpackage/BUILD b/javatests/dagger/hilt/android/testsubpackage/BUILD
index 114c861..287a0ad 100644
--- a/javatests/dagger/hilt/android/testsubpackage/BUILD
+++ b/javatests/dagger/hilt/android/testsubpackage/BUILD
@@ -34,6 +34,18 @@
     ],
 )
 
+android_library(
+    name = "PackagePrivateConstructorTestClasses",
+    srcs = ["PackagePrivateConstructorTestClasses.java"],
+    deps = [
+        "@maven//:androidx_activity_activity",
+        "@maven//:androidx_fragment_fragment",
+        "@maven//:androidx_lifecycle_lifecycle_common",
+        "@maven//:androidx_lifecycle_lifecycle_viewmodel",
+        "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
+    ],
+)
+
 exports_files(srcs = [
     "UsesLocalComponentTestBindingsTest.java",
     "UsesSharedComponent1Test.java",
diff --git a/javatests/dagger/hilt/android/testsubpackage/PackagePrivateConstructorTestClasses.java b/javatests/dagger/hilt/android/testsubpackage/PackagePrivateConstructorTestClasses.java
new file mode 100644
index 0000000..a8ff381
--- /dev/null
+++ b/javatests/dagger/hilt/android/testsubpackage/PackagePrivateConstructorTestClasses.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.hilt.android.testsubpackage;
+
+import android.app.IntentService;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public final class PackagePrivateConstructorTestClasses {
+
+  public abstract static class BaseActivity extends FragmentActivity {
+    public BaseActivity() {}
+
+    BaseActivity(int unused) {}
+  }
+
+  public abstract static class BaseFragment extends Fragment {
+    public BaseFragment() {}
+
+    BaseFragment(int unused) {}
+  }
+
+  public abstract static class BaseView extends LinearLayout {
+    public BaseView(Context context) {
+      super(context);
+    }
+
+    public BaseView(Context context, AttributeSet attrs) {
+      super(context, attrs);
+    }
+
+    public BaseView(Context context, AttributeSet attrs, int defStyleAttr) {
+      super(context, attrs, defStyleAttr);
+    }
+
+    BaseView(Context context, int unused) {
+      super(context);
+    }
+  }
+
+  public abstract static class BaseService extends Service {
+    public BaseService() {}
+
+    BaseService(int unused) {}
+  }
+
+  public abstract static class BaseIntentService extends IntentService {
+    public BaseIntentService(String name) {
+      super(name);
+    }
+
+    BaseIntentService(String name, int unused) {
+      super(name);
+    }
+  }
+
+  public abstract static class BaseBroadcastReceiver extends BroadcastReceiver {
+    public BaseBroadcastReceiver() {}
+
+    BaseBroadcastReceiver(int unused) {}
+  }
+
+}
diff --git a/javatests/dagger/hilt/processor/internal/BUILD b/javatests/dagger/hilt/processor/internal/BUILD
index 3dfe1ea..9cbf6a3 100644
--- a/javatests/dagger/hilt/processor/internal/BUILD
+++ b/javatests/dagger/hilt/processor/internal/BUILD
@@ -15,6 +15,8 @@
 # Description:
 #   Tests for internal code for implementing Hilt processors.
 
+load("@rules_java//java:defs.bzl", "java_library", "java_test")
+
 package(default_visibility = ["//:src"])
 
 java_test(
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
index 9ddf52a..1ad0176 100644
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -32,7 +32,7 @@
         "//java/dagger/hilt:install_in",
         "//java/dagger/hilt/android/testing:hilt_android_test",
         "//java/dagger/hilt/android/components",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
     ],
     deps = [
         "//java/dagger/hilt/android/testing/compile",
diff --git a/javatests/dagger/hilt/processor/internal/aliasof/BUILD b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
index a56e140..da1fd37 100644
--- a/javatests/dagger/hilt/processor/internal/aliasof/BUILD
+++ b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
@@ -24,7 +24,7 @@
     size = "small",
     srcs = ["AliasOfProcessorTest.java"],
     compiler_deps = [
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "//third_party/java/jsr330_inject",
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android/components",
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
index ad919f5..c697141 100644
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -24,7 +24,7 @@
     srcs = ["GeneratesRootInputProcessorTest.java"],
     compiler_deps = [
         "//java/dagger/hilt:generates_root_input",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
     ],
     deps = [
diff --git a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
index 75f56ff..4a551f3 100644
--- a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -24,7 +24,7 @@
     srcs = ["OriginatingElementProcessorTest.java"],
     compiler_deps = [
         "//java/dagger/hilt/codegen:originating_element",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
     ],
     deps = [
diff --git a/javatests/dagger/hilt/processor/internal/root/BUILD b/javatests/dagger/hilt/processor/internal/root/BUILD
index bdc69dc..35efea5 100644
--- a/javatests/dagger/hilt/processor/internal/root/BUILD
+++ b/javatests/dagger/hilt/processor/internal/root/BUILD
@@ -34,7 +34,7 @@
         ":MyAppPreviousCompilation",
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
         "@maven//:org_robolectric_robolectric",
         "@maven//:androidx_test_ext_junit",
@@ -65,7 +65,7 @@
         ":MyTestPreviousCompilation",
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
         "@maven//:org_robolectric_robolectric",
         "@maven//:androidx_test_ext_junit",
@@ -86,7 +86,7 @@
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
         "@maven//:org_robolectric_robolectric",
         "@maven//:androidx_test_ext_junit",
@@ -106,7 +106,7 @@
     compiler_deps = [
         "//java/dagger/hilt/android:hilt_android_app",
         "//java/dagger/hilt/android/testing:hilt_android_test",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
         "@maven//:org_robolectric_robolectric",
         "@maven//:androidx_test_ext_junit",
diff --git a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
index 50ffd2e..e1bd2fb 100644
--- a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -27,7 +27,7 @@
         "//java/dagger/hilt/android/testing:hilt_android_test",
         "//java/dagger/hilt/android/testing:uninstall_modules",
         "//java/dagger/hilt/migration:disable_install_in_check",
-        "@androidsdk//:platforms/android-32/android.jar",
+        "@androidsdk//:platforms/android-34/android.jar",
         "@maven//:androidx_annotation_annotation",
     ],
     deps = [
diff --git a/javatests/dagger/internal/codegen/BUILD b/javatests/dagger/internal/codegen/BUILD
index b189fe5..42d07a6 100644
--- a/javatests/dagger/internal/codegen/BUILD
+++ b/javatests/dagger/internal/codegen/BUILD
@@ -15,7 +15,8 @@
 # Description:
 #   Tests for the Dagger compiler/codegen
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_library")
 load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
 load("//:test_defs.bzl", "GenJavaTests")
 
@@ -72,7 +73,7 @@
         "//third_party/java/guava/collect",
         "//third_party/java/javapoet",
         "//third_party/java/truth",
-        "@com_google_auto_value_auto_value//jar",
+        "@maven//:com_google_auto_value_auto_value",
     ],
 )
 
@@ -110,7 +111,7 @@
     "//third_party/java/guava/collect",
     "//third_party/java/guava/util/concurrent",
     "//third_party/java/auto:value",
-    "@com_google_auto_value_auto_value//jar",
+    "@maven//:com_google_auto_value_auto_value",
     "//third_party/java/auto:common",
     "//third_party/java/compile_testing",
     "//third_party/java/javapoet",
diff --git a/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java b/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java
index 18cc734..a3a7ffa 100644
--- a/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java
@@ -187,4 +187,28 @@
             });
   }
 
+  @Test
+  public void bindsInstanceDaggerProvider() {
+    Source bindsDaggerProvider =
+        CompilerTests.javaSource(
+            "test.BindsInstanceFrameworkType",
+            "package test;",
+            "",
+            "import dagger.BindsInstance;",
+            "import dagger.internal.Provider;",
+            "import dagger.producers.Producer;",
+            "",
+            "interface BindsInstanceFrameworkType {",
+            "  @BindsInstance void bindsProvider(Provider<Object> objectProvider);",
+            "}");
+    CompilerTests.daggerCompiler(bindsDaggerProvider)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("@BindsInstance parameters must not be disallowed types")
+                  .onSource(bindsDaggerProvider)
+                  .onLine(8);
+            });
+  }
 }
diff --git a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
index cb94f75..7806b22 100644
--- a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
@@ -276,7 +276,6 @@
             });
   }
 
-
   @Test
   public void bindsMissingTypeInReturnTypeHierarchy() {
     Source module =
@@ -342,6 +341,107 @@
             });
   }
 
+  @Test
+  public void bindsNullableToNonNullable_fails() {
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.Binds;",
+            "import dagger.Module;",
+            "import javax.annotation.Nullable;",
+            "",
+            "@Module",
+            "interface TestModule {",
+            "  @Binds Object bind(@Nullable String str);",
+            "}");
+
+    CompilerTests.daggerCompiler(module)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "@Binds methods' nullability must match the nullability of its parameter");
+            });
+  }
+
+  @Test
+  public void bindsNonNullableToNullable_fails() {
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.Binds;",
+            "import dagger.Module;",
+            "import javax.annotation.Nullable;",
+            "",
+            "@Module",
+            "interface TestModule {",
+            "  @Binds @Nullable Object bind(String str);",
+            "}");
+
+    CompilerTests.daggerCompiler(module)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "@Binds methods' nullability must match the nullability of its parameter");
+            });
+  }
+
+  // This is a regression test for b/370367984.
+  @Test
+  public void bindsMapKVAndRequestMapKProviderV_failsWithMissingBindingError() {
+    Source component =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "import dagger.Component;",
+            "import javax.inject.Provider;",
+            "import java.util.Map;",
+            "",
+            "@Component(modules = {TestModule.class})",
+            "interface TestComponent {",
+            "  Map<K, Provider<V>> getMap();",
+            "}");
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestModule",
+            "package test;",
+            "import dagger.Binds;",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import java.util.Map;",
+            "",
+            "@Module",
+            "interface TestModule {",
+            "  @Binds Map<K, V> bind(@TestQualifier Map<K, V> impl);",
+            "",
+            "  @Provides",
+            "  @TestQualifier",
+            "  static Map<K, V> provideMap() {",
+            "    return (Map<K, V>) null;",
+            "  }",
+            "}");
+    Source qualifier =
+        CompilerTests.javaSource(
+            "test.TestQualifier",
+            "package test;",
+            "import javax.inject.Qualifier;",
+            "",
+            "@Qualifier @interface TestQualifier {}");
+    Source k = CompilerTests.javaSource("test.K", "package test;", "interface K {}");
+    Source v = CompilerTests.javaSource("test.V", "package test;", "interface V {}");
+    CompilerTests.daggerCompiler(component, module, qualifier, k, v)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("Map<test.K,Provider<test.V>> cannot be provided");
+            });
+  }
+
   private DaggerModuleMethodSubject assertThatMethod(String method) {
     return assertThatModuleMethod(method).withDeclaration(moduleDeclaration);
   }
diff --git a/javatests/dagger/internal/codegen/CompilerMode.java b/javatests/dagger/internal/codegen/CompilerMode.java
index 7f167d7..57a9455 100644
--- a/javatests/dagger/internal/codegen/CompilerMode.java
+++ b/javatests/dagger/internal/codegen/CompilerMode.java
@@ -28,10 +28,7 @@
 // TODO(bcorso): Consider moving the java version into its own separate enum.
 public enum CompilerMode {
   DEFAULT_MODE,
-  DEFAULT_JAVA7_MODE("-source", "7", "-target", "7"),
-  FAST_INIT_MODE("-Adagger.fastInit=enabled"),
-  FAST_INIT_JAVA7_MODE("-Adagger.fastInit=enabled", "-source", "7", "-target", "7"),
-  ;
+  FAST_INIT_MODE("-Adagger.fastInit=enabled");
 
   /** Returns the compiler modes as a list of parameters for parameterized tests */
   public static final ImmutableList<Object[]> TEST_PARAMETERS =
diff --git a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
index 65929e7..dfe74bb 100644
--- a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
+++ b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
@@ -33,6 +33,13 @@
     return CompilerMode.TEST_PARAMETERS;
   }
 
+  private static final Source NON_TYPE_USE_NULLABLE =
+      CompilerTests.javaSource(
+          "test.Nullable", // force one-string-per-line format
+          "package test;",
+          "",
+          "public @interface Nullable {}");
+
   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
 
   private final CompilerMode compilerMode;
@@ -74,6 +81,38 @@
   }
 
   @Test
+  public void testBindsNullableInstance() throws Exception {
+    Source component =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.BindsInstance;",
+            "import dagger.Component;",
+            "",
+            "@Component",
+            "interface TestComponent {",
+            "  @Component.Factory",
+            "  interface Factory {",
+            "    TestComponent create(@BindsInstance @Nullable Bar arg);",
+            "}",
+            "}");
+    Source bar =
+        CompilerTests.javaSource(
+            "test.Bar", // force one-string-per-line format
+            "package test;",
+            "",
+            "interface Bar {}");
+    CompilerTests.daggerCompiler(component, bar, NON_TYPE_USE_NULLABLE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
+            });
+  }
+
+  @Test
   public void instanceModuleMethod() throws Exception {
     Source module =
         CompilerTests.javaSource(
diff --git a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
index 7092047..dffe701 100644
--- a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
+++ b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
@@ -124,8 +124,17 @@
               assertThrows(
                   ValidationException.KnownErrorType.class,
                   () -> superficialValidation.validateElement(testClassElement));
-          // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
-          boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+          final String errorType;
+          if (processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC) {
+            // JDK 24 improves error type information.
+            errorType =
+                Runtime.version().feature() >= 24
+                    ? isKAPT(processingEnv) ? "MissingType" : "MissingType<?>"
+                    : "<any>";
+          } else {
+            // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+            errorType = "error.NonExistentClass";
+          }
           assertThat(exception)
               .hasMessageThat()
               .contains(
@@ -135,7 +144,7 @@
                           "  => element (CLASS): test.TestClass",
                           "  => element (METHOD): blah()",
                           "  => type (ERROR return type): %1$s"),
-                      isJavac ? "<any>" : "error.NonExistentClass"));
+                      errorType));
         });
   }
 
@@ -165,8 +174,14 @@
               assertThrows(
                   ValidationException.KnownErrorType.class,
                   () -> superficialValidation.validateElement(testClassElement));
-          // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
-          boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+          final String errorType;
+          if (processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC) {
+            // JDK 24 improves error type information.
+            errorType = Runtime.version().feature() >= 24 ? "MissingType<?>" : "<any>";
+          } else {
+            // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+            errorType = "error.NonExistentClass";
+          }
           assertThat(exception)
               .hasMessageThat()
               .contains(
@@ -178,7 +193,7 @@
                           "  => type (DECLARED return type): "
                               + "java.util.Map<java.util.Set<?>,%1$s>",
                           "  => type (ERROR type argument): %1$s"),
-                      isJavac ? "<any>" : "error.NonExistentClass"));
+                      errorType));
         });
   }
 
@@ -197,7 +212,7 @@
             "class TestClass<T : MissingType>"),
         (processingEnv, superficialValidation) -> {
           if (isKAPT(processingEnv)) {
-            // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
+            // The KAPT java stub doesn't reference the MissingType symbol (b/268536260#comment2).
             return;
           }
           XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
@@ -402,7 +417,7 @@
             "class TestClass<T> where T: Number, T: Missing"),
         (processingEnv, superficialValidation) -> {
           if (isKAPT(processingEnv)) {
-            // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
+            // The KAPT java stub doesn't reference the MissingType symbol (b/268536260#comment2).
             return;
           }
           XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
@@ -454,31 +469,29 @@
             "}"),
         (processingEnv, superficialValidation) -> {
           XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass");
-          if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP
-              && sourceKind == SourceKind.KOTLIN) {
-            // TODO(b/269364338): When using kotlin source with KSP the MissingType annotation value
-            // appears to be missing so validating this element does not cause the expected failure.
-            superficialValidation.validateElement(testClassElement);
-            return;
-          }
           ValidationException exception =
               assertThrows(
                   ValidationException.KnownErrorType.class,
                   () -> superficialValidation.validateElement(testClassElement));
           // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
           boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
-          assertThat(exception)
-              .hasMessageThat()
-              .contains(
-                  String.format(
-                      NEW_LINES.join(
-                          "Validation trace:",
-                          "  => element (CLASS): test.Outer.TestClass",
-                          "  => annotation type: test.Outer.TestAnnotation",
-                          "  => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
-                          "  => annotation value (TYPE_ARRAY): classes={<%1$s>}",
-                          "  => annotation value (TYPE): classes=<%1$s>"),
-                      isJavac ? "error" : "Error"));
+          String expectedMessage =
+              String.format(
+                  NEW_LINES.join(
+                      "Validation trace:",
+                      "  => element (CLASS): test.Outer.TestClass",
+                      "  => annotation type: test.Outer.TestAnnotation",
+                      "  => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
+                      "  => annotation value (TYPE_ARRAY): classes={<%1$s>}",
+                      "  => annotation value (TYPE): classes=<%1$s>"),
+                  isJavac ? "error" : "ERROR TYPE: MissingType");
+          if (!isJavac) {
+            expectedMessage =
+                NEW_LINES.join(
+                    expectedMessage,
+                    "  => type (ERROR annotation value type): error.NonExistentClass");
+          }
+          assertThat(exception).hasMessageThat().contains(expectedMessage);
         });
   }
 
@@ -512,10 +525,8 @@
             "  )",
             "}"),
         (processingEnv, superficialValidation) -> {
-          if (sourceKind == SourceKind.KOTLIN) {
-            // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
-            // TODO(b/269364338): When using kotlin source the MissingType annotation value appears
-            // to be missing so validating this element does not cause the expected failure.
+          if (isKAPT(processingEnv)) {
+            // The KAPT java stub doesn't reference the MissingType symbol (b/268536260#comment2).
             return;
           }
           XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass");
@@ -527,20 +538,25 @@
                   () -> superficialValidation.validateElement(parameter));
           // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
           boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
-          assertThat(exception)
-              .hasMessageThat()
-              .contains(
-                  String.format(
-                      NEW_LINES.join(
-                          "Validation trace:",
-                          "  => element (CLASS): test.Outer.TestClass",
-                          "  => element (CONSTRUCTOR): TestClass(java.lang.String)",
-                          "  => element (PARAMETER): strParam",
-                          "  => annotation type: test.Outer.TestAnnotation",
-                          "  => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
-                          "  => annotation value (TYPE_ARRAY): classes={<%1$s>}",
-                          "  => annotation value (TYPE): classes=<%1$s>"),
-                      isJavac ? "error" : "Error"));
+          String expectedMessage =
+              String.format(
+                  NEW_LINES.join(
+                      "Validation trace:",
+                      "  => element (CLASS): test.Outer.TestClass",
+                      "  => element (CONSTRUCTOR): TestClass(java.lang.String)",
+                      "  => element (PARAMETER): strParam",
+                      "  => annotation type: test.Outer.TestAnnotation",
+                      "  => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
+                      "  => annotation value (TYPE_ARRAY): classes={<%1$s>}",
+                      "  => annotation value (TYPE): classes=<%1$s>"),
+                  isJavac ? "error" : "ERROR TYPE: MissingType");
+          if (!isJavac) {
+            expectedMessage =
+                NEW_LINES.join(
+                    expectedMessage,
+                    "  => type (ERROR annotation value type): error.NonExistentClass");
+          }
+          assertThat(exception).hasMessageThat().contains(expectedMessage);
         });
   }
 
diff --git a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
index e759bdc..7332351 100644
--- a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
+++ b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
@@ -16,15 +16,10 @@
 
 package dagger.internal.codegen;
 
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.TestUtils.endsWithMessage;
-
 import androidx.room.compiler.processing.util.Source;
 import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
+import com.google.common.collect.ImmutableMap;
 import dagger.testing.compile.CompilerTests;
-import java.util.regex.Pattern;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -90,66 +85,87 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.CComponent] Outer.A(cParam)",
                           "    Outer.A is injected at",
-                          "        Outer.B(aParam)",
+                          "        [Outer.CComponent] Outer.B(aParam)",
                           "    Outer.B is injected at",
-                          "        Outer.C(bParam)",
+                          "        [Outer.CComponent] Outer.C(bParam)",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.CComponent] Outer.A(cParam)",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    Outer.C is requested at",
-                          "        Outer.CComponent.getC()"))
+                          "        [Outer.CComponent] Outer.CComponent.getC()"))
                   .onSource(SIMPLE_CYCLIC_DEPENDENCY)
                   .onLineContaining("interface CComponent");
             });
   }
 
-  // TODO(b/243720787): Requires CompilationResultSubject#hasErrorContainingMatch()
   @Test
   public void cyclicDependencyWithModuleBindingValidation() {
     // Cycle errors should not show a dependency trace to an entry point when doing full binding
     // graph validation. So ensure that the message doesn't end with "test.Outer.C is requested at
     // test.Outer.CComponent.getC()", as the previous test's message does.
-    Pattern moduleBindingValidationError =
-        endsWithMessage(
-            "Found a dependency cycle:",
-            "    Outer.C is injected at",
-            "        Outer.A(cParam)",
-            "    Outer.A is injected at",
-            "        Outer.B(aParam)",
-            "    Outer.B is injected at",
-            "        Outer.C(bParam)",
-            "    Outer.C is injected at",
-            "        Outer.A(cParam)",
-            "    ...",
-            "",
-            "======================",
-            "Full classname legend:",
-            "======================",
-            "Outer: test.Outer",
-            "========================",
-            "End of classname legend:",
-            "========================");
+    CompilerTests.daggerCompiler(SIMPLE_CYCLIC_DEPENDENCY)
+        .withProcessingOptions(
+            ImmutableMap.<String, String>builder()
+                .put("dagger.fullBindingGraphValidation", "ERROR")
+                .putAll(compilerMode.processorOptions())
+                .buildOrThrow())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject
+                  .hasErrorContaining(
+                      String.join(
+                          "\n",
+                          "Found a dependency cycle:",
+                          "    Outer.C is injected at",
+                          "        [Outer.MModule] Outer.A(cParam)",
+                          "    Outer.A is injected at",
+                          "        [Outer.MModule] Outer.B(aParam)",
+                          "    Outer.B is injected at",
+                          "        [Outer.MModule] Outer.C(bParam)",
+                          "    Outer.C is injected at",
+                          "        [Outer.MModule] Outer.A(cParam)",
+                          "    ...",
+                          "",
+                          "======================",
+                          "Full classname legend:",
+                          "======================",
+                          "Outer: test.Outer",
+                          "========================",
+                          "End of classname legend:",
+                          "========================"))
+                  .onSource(SIMPLE_CYCLIC_DEPENDENCY)
+                  .onLineContaining("interface MModule");
 
-    Compilation compilation =
-        compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
-            .compile(SIMPLE_CYCLIC_DEPENDENCY.toJFO());
-    assertThat(compilation).failed();
-
-    assertThat(compilation)
-        .hadErrorContainingMatch(moduleBindingValidationError)
-        .inFile(SIMPLE_CYCLIC_DEPENDENCY.toJFO())
-        .onLineContaining("interface MModule");
-
-    assertThat(compilation)
-        .hadErrorContainingMatch(moduleBindingValidationError)
-        .inFile(SIMPLE_CYCLIC_DEPENDENCY.toJFO())
-        .onLineContaining("interface CComponent");
-
-    assertThat(compilation).hadErrorCount(2);
+              subject
+                  .hasErrorContaining(
+                      String.join(
+                          "\n",
+                          "Found a dependency cycle:",
+                          "    Outer.C is injected at",
+                          "        [Outer.CComponent] Outer.A(cParam)",
+                          "    Outer.A is injected at",
+                          "        [Outer.CComponent] Outer.B(aParam)",
+                          "    Outer.B is injected at",
+                          "        [Outer.CComponent] Outer.C(bParam)",
+                          "    Outer.C is injected at",
+                          "        [Outer.CComponent] Outer.A(cParam)",
+                          "    ...",
+                          "",
+                          "======================",
+                          "Full classname legend:",
+                          "======================",
+                          "Outer: test.Outer",
+                          "========================",
+                          "End of classname legend:",
+                          "========================"))
+                  .onSource(SIMPLE_CYCLIC_DEPENDENCY)
+                  .onLineContaining("interface CComponent");
+            });
   }
 
   @Test public void cyclicDependencyNotIncludingEntryPoint() {
@@ -196,20 +212,20 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.DComponent] Outer.A(cParam)",
                           "    Outer.A is injected at",
-                          "        Outer.B(aParam)",
+                          "        [Outer.DComponent] Outer.B(aParam)",
                           "    Outer.B is injected at",
-                          "        Outer.C(bParam)",
+                          "        [Outer.DComponent] Outer.C(bParam)",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.DComponent] Outer.A(cParam)",
                           "   ...",
                           "",
                           "The cycle is requested via:",
                           "    Outer.C is injected at",
-                          "        Outer.D(cParam)",
+                          "        [Outer.DComponent] Outer.D(cParam)",
                           "    Outer.D is requested at",
-                          "        Outer.DComponent.getD()"))
+                          "        [Outer.DComponent] Outer.DComponent.getD()"))
                   .onSource(component)
                   .onLineContaining("interface DComponent");
             });
@@ -268,20 +284,20 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Outer.C is injected at",
-                          "        Outer.CModule.c(c)",
+                          "        [Outer.CComponent] Outer.CModule.c(c)",
                           "    Map<String,Outer.C> is injected at",
-                          "        Outer.A(cMap)",
+                          "        [Outer.CComponent] Outer.A(cMap)",
                           "    Outer.A is injected at",
-                          "        Outer.B(aParam)",
+                          "        [Outer.CComponent] Outer.B(aParam)",
                           "    Outer.B is injected at",
-                          "        Outer.C(bParam)",
+                          "        [Outer.CComponent] Outer.C(bParam)",
                           "    Outer.C is injected at",
-                          "        Outer.CModule.c(c)",
+                          "        [Outer.CComponent] Outer.CModule.c(c)",
                           "   ...",
                           "",
                           "The cycle is requested via:",
                           "    Outer.C is requested at",
-                          "        Outer.CComponent.getC()"))
+                          "        [Outer.CComponent] Outer.CComponent.getC()"))
                   .onSource(component)
                   .onLineContaining("interface CComponent");
             });
@@ -338,20 +354,20 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Outer.C is injected at",
-                          "        Outer.CModule.c(c)",
+                          "        [Outer.CComponent] Outer.CModule.c(c)",
                           "    Set<Outer.C> is injected at",
-                          "        Outer.A(cSet)",
+                          "        [Outer.CComponent] Outer.A(cSet)",
                           "    Outer.A is injected at",
-                          "        Outer.B(aParam)",
+                          "        [Outer.CComponent] Outer.B(aParam)",
                           "    Outer.B is injected at",
-                          "        Outer.C(bParam)",
+                          "        [Outer.CComponent] Outer.C(bParam)",
                           "    Outer.C is injected at",
-                          "        Outer.CModule.c(c)",
+                          "        [Outer.CComponent] Outer.CModule.c(c)",
                           "   ...",
                           "",
                           "The cycle is requested via:",
                           "    Outer.C is requested at",
-                          "        Outer.CComponent.getC()"))
+                          "        [Outer.CComponent] Outer.CComponent.getC()"))
                   .onSource(component)
                   .onLineContaining("interface CComponent");
             });
@@ -403,20 +419,20 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.DComponent] Outer.A(cParam)",
                           "    Outer.A is injected at",
-                          "        Outer.B(aParam)",
+                          "        [Outer.DComponent] Outer.B(aParam)",
                           "    Outer.B is injected at",
-                          "        Outer.C(bParam)",
+                          "        [Outer.DComponent] Outer.C(bParam)",
                           "    Outer.C is injected at",
-                          "        Outer.A(cParam)",
+                          "        [Outer.DComponent] Outer.A(cParam)",
                           "   ...",
                           "",
                           "The cycle is requested via:",
                           "    Provider<Outer.C> is injected at",
-                          "        Outer.D(cParam)",
+                          "        [Outer.DComponent] Outer.D(cParam)",
                           "    Outer.D is requested at",
-                          "        Outer.DComponent.getD()"))
+                          "        [Outer.DComponent] Outer.DComponent.getD()"))
                   .onSource(component)
                   .onLineContaining("interface DComponent");
             });
@@ -496,16 +512,16 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    String is injected at",
-                          "        CycleModule.object(string)",
+                          "        [Child] CycleModule.object(string)",
                           "    Object is injected at",
-                          "        CycleModule.string(object)",
+                          "        [Child] CycleModule.string(object)",
                           "    String is injected at",
-                          "        CycleModule.object(string)",
+                          "        [Child] CycleModule.object(string)",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    String is requested at",
-                          "        Grandchild.entry()"))
+                          "        [Grandchild] Grandchild.entry()"))
                   .onSource(parent)
                   .onLineContaining("interface Parent");
             });
@@ -587,16 +603,16 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    String is injected at",
-                          "        CycleModule.object(string)",
+                          "        [Child] CycleModule.object(string)",
                           "    Object is injected at",
-                          "        CycleModule.string(object)",
+                          "        [Child] CycleModule.string(object)",
                           "    String is injected at",
-                          "        CycleModule.object(string)",
+                          "        [Child] CycleModule.object(string)",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    String is requested at",
-                          "        Child.entry() [Parent → Child]"))
+                          "        [Child] Child.entry() [Parent → Child]"))
                   .onSource(parent)
                   .onLineContaining("interface Parent");
             });
@@ -647,16 +663,16 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Object is injected at",
-                          "        TestModule.bindQualified(unqualified)",
+                          "        [TestComponent] TestModule.bindQualified(unqualified)",
                           "    @SomeQualifier Object is injected at",
-                          "        TestModule.bindUnqualified(qualified)",
+                          "        [TestComponent] TestModule.bindUnqualified(qualified)",
                           "    Object is injected at",
-                          "        TestModule.bindQualified(unqualified)",
+                          "        [TestComponent] TestModule.bindQualified(unqualified)",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    Object is requested at",
-                          "        TestComponent.unqualified()"))
+                          "        [TestComponent] TestComponent.unqualified()"))
                   .onSource(component)
                   .onLineContaining("interface TestComponent");
             });
@@ -698,14 +714,14 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    Object is injected at",
-                          "        TestModule.bindToSelf(sameKey)",
+                          "        [TestComponent] TestModule.bindToSelf(sameKey)",
                           "    Object is injected at",
-                          "        TestModule.bindToSelf(sameKey)",
+                          "        [TestComponent] TestModule.bindToSelf(sameKey)",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    Object is requested at",
-                          "        TestComponent.selfReferential()"))
+                          "        [TestComponent] TestComponent.selfReferential()"))
                   .onSource(component)
                   .onLineContaining("interface TestComponent");
             });
@@ -757,18 +773,18 @@
                           "\n",
                           "Found a dependency cycle:",
                           "    test.B is injected at",
-                          "        test.A.b",
+                          "        [CycleComponent] test.A.b",
                           "    test.A is injected at",
-                          "        test.B.a",
+                          "        [CycleComponent] test.B.a",
                           "    test.B is injected at",
-                          "        test.A.b",
+                          "        [CycleComponent] test.A.b",
                           "    ...",
                           "",
                           "The cycle is requested via:",
                           "    test.B is injected at",
-                          "        test.A.b",
+                          "        [CycleComponent] test.A.b",
                           "    test.A is injected at",
-                          "        CycleComponent.inject(test.A)"))
+                          "        [CycleComponent] CycleComponent.inject(test.A)"))
                   .onSource(component)
                   .onLineContaining("interface CycleComponent");
             });
diff --git a/javatests/dagger/internal/codegen/FrameworkFieldTest.java b/javatests/dagger/internal/codegen/FrameworkFieldTest.java
index ba5b88f..2592c35 100644
--- a/javatests/dagger/internal/codegen/FrameworkFieldTest.java
+++ b/javatests/dagger/internal/codegen/FrameworkFieldTest.java
@@ -17,16 +17,19 @@
 package dagger.internal.codegen;
 
 import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTOR;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
-import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static dagger.internal.codegen.xprocessing.XTypeNames.MEMBERS_INJECTOR;
+import static dagger.internal.codegen.xprocessing.XTypeNames.PROVIDER;
+import static dagger.internal.codegen.xprocessing.XTypeNames.membersInjectorOf;
+import static dagger.internal.codegen.xprocessing.XTypeNames.providerOf;
 
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
 import com.google.testing.compile.CompilationRule;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.ParameterizedTypeName;
+import dagger.Component;
 import dagger.internal.codegen.binding.FrameworkField;
+import dagger.internal.codegen.javac.JavacPluginModule;
 import javax.inject.Inject;
+import javax.inject.Singleton;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -40,32 +43,40 @@
 public class FrameworkFieldTest {
   @Rule public CompilationRule compilationRule = new CompilationRule();
 
-  private ClassName xTypeName;
+  @Inject XProcessingEnv processingEnv;
 
-  @Before public void setUp() {
-    xTypeName =
-        ClassName.get(compilationRule.getElements().getTypeElement(X.class.getCanonicalName()));
+  private XType type;
+
+  @Before
+  public void setUp() {
+    DaggerFrameworkFieldTest_TestComponent.builder()
+        .javacPluginModule(
+            new JavacPluginModule(compilationRule.getElements(), compilationRule.getTypes()))
+        .build()
+        .inject(this);
+    type = processingEnv.requireType(X.class.getCanonicalName());
   }
 
   @Test public void frameworkType() {
-    assertThat(FrameworkField.create(ParameterizedTypeName.get(PROVIDER, xTypeName), "test").type())
-        .isEqualTo(providerOf(xTypeName));
-    assertThat(
-            FrameworkField.create(ParameterizedTypeName.get(MEMBERS_INJECTOR, xTypeName), "test")
-                .type())
-        .isEqualTo(membersInjectorOf(xTypeName));
+    assertThat(FrameworkField.create("test", PROVIDER, type).type())
+        .isEqualTo(providerOf(type.asTypeName()));
+    assertThat(FrameworkField.create("test", MEMBERS_INJECTOR, type).type())
+        .isEqualTo(membersInjectorOf(type.asTypeName()));
   }
 
   @Test public void nameSuffix() {
-    assertThat(FrameworkField.create(ParameterizedTypeName.get(PROVIDER, xTypeName), "foo").name())
-        .isEqualTo("fooProvider");
-    assertThat(
-            FrameworkField.create(ParameterizedTypeName.get(PROVIDER, xTypeName), "fooProvider")
-                .name())
+    assertThat(FrameworkField.create("foo", PROVIDER, type).name()).isEqualTo("fooProvider");
+    assertThat(FrameworkField.create("fooProvider", PROVIDER, type).name())
         .isEqualTo("fooProvider");
   }
 
   static final class X {
     @Inject X() {}
   }
-}
+
+  @Singleton
+  @Component(modules = JavacPluginModule.class)
+  interface TestComponent {
+    void inject(FrameworkFieldTest test);
+  }
+}
\ No newline at end of file
diff --git a/javatests/dagger/internal/codegen/GeneratedLines.java b/javatests/dagger/internal/codegen/GeneratedLines.java
index d8a0388..f75fca8 100644
--- a/javatests/dagger/internal/codegen/GeneratedLines.java
+++ b/javatests/dagger/internal/codegen/GeneratedLines.java
@@ -33,7 +33,9 @@
 
   private static final String SUPPRESS_WARNINGS_ANNOTATION =
       "@SuppressWarnings({"
-          + "\"unchecked\", \"rawtypes\", \"KotlinInternal\", \"KotlinInternalInJava\", \"cast\""
+          + "\"unchecked\", \"rawtypes\", \"KotlinInternal\", \"KotlinInternalInJava\", \"cast\", "
+          + "\"deprecation\","
+          + "\"nullness:initialization.field.uninitialized\""
           + "})";
 
   private static final String IMPORT_DAGGER_GENERATED = "import dagger.internal.DaggerGenerated;";
diff --git a/javatests/dagger/internal/codegen/InaccessibleTypeBindsTest.java b/javatests/dagger/internal/codegen/InaccessibleTypeBindsTest.java
index f4eda9c..8d2f728 100644
--- a/javatests/dagger/internal/codegen/InaccessibleTypeBindsTest.java
+++ b/javatests/dagger/internal/codegen/InaccessibleTypeBindsTest.java
@@ -23,7 +23,6 @@
 import com.google.testing.compile.Compilation;
 import com.google.testing.compile.JavaFileObjects;
 import dagger.testing.golden.GoldenFileRule;
-import java.util.Collection;
 import javax.tools.JavaFileObject;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,16 +33,8 @@
 @RunWith(Parameterized.class)
 public class InaccessibleTypeBindsTest {
   @Parameters(name = "{0}")
-  public static Collection<Object[]> parameters() {
-    return ImmutableList.copyOf(
-        new Object[][] {
-            {CompilerMode.DEFAULT_MODE},
-            {CompilerMode.DEFAULT_JAVA7_MODE},
-            {CompilerMode.FAST_INIT_MODE},
-            // FastInit with Java7 is the mode that motivated this test, but do the other
-            // modes anyway for completeness.
-            {CompilerMode.FAST_INIT_JAVA7_MODE}
-        });
+  public static ImmutableList<Object[]> parameters() {
+    return CompilerMode.TEST_PARAMETERS;
   }
 
   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
diff --git a/javatests/dagger/internal/codegen/LazyClassKeyMapBindingComponentProcessorTest.java b/javatests/dagger/internal/codegen/LazyClassKeyMapBindingComponentProcessorTest.java
index 9937d05..444040a 100644
--- a/javatests/dagger/internal/codegen/LazyClassKeyMapBindingComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/LazyClassKeyMapBindingComponentProcessorTest.java
@@ -16,13 +16,19 @@
 
 package dagger.internal.codegen;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.testing.compile.CompilationSubject.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 import androidx.room.compiler.processing.util.Source;
+import com.google.common.truth.PrimitiveByteArraySubject;
+import com.google.common.truth.StringSubject;
+import com.google.common.truth.Subject;
 import com.google.testing.compile.Compilation;
 import com.google.testing.compile.JavaFileObjects;
 import dagger.testing.compile.CompilerTests;
 import dagger.testing.golden.GoldenFileRule;
+import java.lang.reflect.Method;
 import java.util.Collection;
 import javax.tools.JavaFileObject;
 import org.junit.Rule;
@@ -186,6 +192,303 @@
             "}");
     CompilerTests.daggerCompiler(fooBar, fooBar2, mapKeyBindingsModule, componentFile)
         .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
+            });
+  }
+
+  @Test
+  public void lazyClassKeyProvider_compilesSuccessfully() throws Exception {
+    Source fooBar =
+        CompilerTests.javaSource("test.Foo_Bar", "package test;", "", "interface Foo_Bar {}");
+    Source fooBar2 =
+        CompilerTests.javaSource(
+            "test.Foo", "package test;", "", "interface Foo { interface Bar {} }");
+    Source mapKeyBindingsModule =
+        CompilerTests.javaSource(
+            "test.MapKeyBindingsModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface MapKeyBindingsModule {",
+            " @Provides @IntoMap @LazyClassKey(test.Foo_Bar.class)",
+            " static int classKey() { return 1; }",
+            "}");
+
+    Source componentFile =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import javax.inject.Provider;",
+            "import java.util.Map;",
+            "",
+            "@Component(modules = MapKeyBindingsModule.class)",
+            "interface TestComponent {",
+            "  Map<Class<?>, Provider<Integer>> classKey();",
+            "}");
+    CompilerTests.daggerCompiler(fooBar, fooBar2, mapKeyBindingsModule, componentFile)
+        .withProcessingOptions(compilerMode.processorOptions())
         .compile(subject -> subject.hasErrorCount(0));
   }
+
+  @Test
+  public void scopedLazyClassKeyProvider_compilesSuccessfully() throws Exception {
+    Source fooBar =
+        CompilerTests.javaSource("test.Foo_Bar", "package test;", "", "interface Foo_Bar {}");
+    Source fooBar2 =
+        CompilerTests.javaSource(
+            "test.Foo", "package test;", "", "interface Foo { interface Bar {} }");
+    Source mapKeyBindingsModule =
+        CompilerTests.javaSource(
+            "test.MapKeyBindingsModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface MapKeyBindingsModule {",
+            " @Provides @IntoMap @LazyClassKey(test.Foo_Bar.class)",
+            " static int classKey() { return 1; }",
+            "}");
+
+    Source componentFile =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import javax.inject.Singleton;",
+            "import javax.inject.Provider;",
+            "import java.util.Map;",
+            "",
+            "@Component(modules = MapKeyBindingsModule.class)",
+            "@Singleton",
+            "interface TestComponent {",
+            "  Provider<Map<Class<?>, Provider<Integer>>> classKey();",
+            "}");
+    CompilerTests.daggerCompiler(fooBar, fooBar2, mapKeyBindingsModule, componentFile)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(subject -> subject.hasErrorCount(0));
+  }
+
+  @Test
+  public void testProguardFile() throws Exception {
+    Source fooKey =
+        CompilerTests.javaSource(
+            "test.FooKey",
+            "package test;",
+            "",
+            "interface FooKey {}");
+    Source fooKeyModule =
+        CompilerTests.javaSource(
+            "test.FooKeyModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface FooKeyModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @LazyClassKey(FooKey.class)",
+            "  static String provideString() { return \"\"; }",
+            "}");
+    CompilerTests.daggerCompiler(fooKey, fooKeyModule)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              PrimitiveByteArraySubject proguardFile =
+                  subject.generatedResourceFileWithPath(
+                      "META-INF/proguard/test_FooKeyModule_LazyClassKeys.pro");
+              assertThatContentAsUtf8String(proguardFile)
+                .isEqualTo("-keep,allowobfuscation,allowshrinking class test.FooKey");
+            });
+  }
+
+  @Test
+  public void testProguardFile_nestedModule() throws Exception {
+    Source fooKey =
+        CompilerTests.javaSource(
+            "test.FooKey",
+            "package test;",
+            "",
+            "interface FooKey {}");
+    Source outerClass =
+        CompilerTests.javaSource(
+            "test.OuterClass",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "public interface OuterClass {",
+            "  @Module",
+            "  public interface FooKeyModule {",
+            "    @Provides",
+            "    @IntoMap",
+            "    @LazyClassKey(FooKey.class)",
+            "    static String provideString() { return \"\"; }",
+            "  }",
+            "}");
+    CompilerTests.daggerCompiler(fooKey, outerClass)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              PrimitiveByteArraySubject proguardFile =
+                  subject.generatedResourceFileWithPath(
+                      "META-INF/proguard/test_OuterClass_FooKeyModule_LazyClassKeys.pro");
+              assertThatContentAsUtf8String(proguardFile)
+                .isEqualTo("-keep,allowobfuscation,allowshrinking class test.FooKey");
+            });
+  }
+
+  @Test
+  public void testProguardFile_multipleModules() throws Exception {
+    Source fooKey =
+        CompilerTests.javaSource(
+            "test.FooKey",
+            "package test;",
+            "",
+            "interface FooKey {}");
+    Source barKey =
+        CompilerTests.javaSource(
+            "test.BarKey",
+            "package test;",
+            "",
+            "interface BarKey {}");
+    Source fooKeyModule =
+        CompilerTests.javaSource(
+            "test.FooKeyModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface FooKeyModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @LazyClassKey(FooKey.class)",
+            "  static String provideString() { return \"\"; }",
+            "}");
+    Source barKeyModule =
+        CompilerTests.javaSource(
+            "test.BarKeyModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface BarKeyModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @LazyClassKey(BarKey.class)",
+            "  static String provideString() { return \"\"; }",
+            "}");
+    CompilerTests.daggerCompiler(fooKey, fooKeyModule, barKey, barKeyModule)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              PrimitiveByteArraySubject fooKeyModuleProguardFile =
+                  subject.generatedResourceFileWithPath(
+                      "META-INF/proguard/test_FooKeyModule_LazyClassKeys.pro");
+              assertThatContentAsUtf8String(fooKeyModuleProguardFile)
+                .isEqualTo("-keep,allowobfuscation,allowshrinking class test.FooKey");
+
+              PrimitiveByteArraySubject barKeyModuleProguardFile =
+                  subject.generatedResourceFileWithPath(
+                      "META-INF/proguard/test_BarKeyModule_LazyClassKeys.pro");
+              assertThatContentAsUtf8String(barKeyModuleProguardFile)
+                .isEqualTo("-keep,allowobfuscation,allowshrinking class test.BarKey");
+            });
+  }
+
+  @Test
+  public void testProguardFile_multipleKeys() throws Exception {
+    Source fooKey =
+        CompilerTests.javaSource(
+            "test.FooKey",
+            "package test;",
+            "",
+            "interface FooKey {}");
+    Source barKey =
+        CompilerTests.javaSource(
+            "test.BarKey",
+            "package test;",
+            "",
+            "interface BarKey {}");
+    Source fooKeyAndBarKeyModule =
+        CompilerTests.javaSource(
+            "test.FooKeyAndBarKeyModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.LazyClassKey;",
+            "import dagger.multibindings.IntoMap;",
+            "",
+            "@Module",
+            "public interface FooKeyAndBarKeyModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @LazyClassKey(FooKey.class)",
+            "  static String provideFooKeyString() { return \"\"; }",
+            "",
+            "  @Provides",
+            "  @IntoMap",
+            "  @LazyClassKey(BarKey.class)",
+            "  static String provideBarKeyString() { return \"\"; }",
+            "}");
+    CompilerTests.daggerCompiler(fooKey, barKey, fooKeyAndBarKeyModule)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              PrimitiveByteArraySubject proguardFile =
+                  subject.generatedResourceFileWithPath(
+                      "META-INF/proguard/test_FooKeyAndBarKeyModule_LazyClassKeys.pro");
+              assertThatContentAsUtf8String(proguardFile)
+                .isEqualTo(
+                    "-keep,allowobfuscation,allowshrinking class test.FooKey\n"
+                      + "-keep,allowobfuscation,allowshrinking class test.BarKey");
+            });
+  }
+
+  // TODO(b/386213524): Add support for getting a resource file as a StringSubject.
+  // Use reflection to get the subject's byte array and then convert it to a StringSubject.
+  private static StringSubject assertThatContentAsUtf8String(PrimitiveByteArraySubject subject) {
+    try {
+      Method protectedActualMethod = Subject.class.getDeclaredMethod("actual");
+      protectedActualMethod.setAccessible(true);
+      byte[] actualBytes = (byte[]) protectedActualMethod.invoke(subject);
+      return assertThat(new String(actualBytes, UTF_8));
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
 }
diff --git a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
index 85f5a5c..c1914c1 100644
--- a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
@@ -137,4 +137,67 @@
         .and()
         .generatesSources(generatedKeyCreator);
   }
+
+  @Test
+  public void nestedComplexMapKey_buildSuccessfully() {
+    JavaFileObject outerKey =
+        JavaFileObjects.forSourceLines(
+            "test.OuterKey",
+            "package test;",
+            "import dagger.MapKey;",
+            "import java.lang.annotation.Retention;",
+            "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+            "",
+            "@MapKey(unwrapValue = false)",
+            "public @interface OuterKey {",
+            "  String value() default \"hello\";",
+            "  NestedKey[] nestedKeys() default {};",
+            "}");
+    JavaFileObject nestedKey =
+        JavaFileObjects.forSourceLines(
+            "test.NestedKey",
+            "package test;",
+            "import dagger.MapKey;",
+            "import java.lang.annotation.Retention;",
+            "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+            "",
+            "@MapKey(unwrapValue = false)",
+            "public @interface NestedKey {",
+            " String value() default \"hello\";",
+            " String otherValue() default \"world\";",
+            "}");
+    JavaFileObject foo =
+        JavaFileObjects.forSourceLines(
+            "test.FooModule",
+            "package test;",
+            "",
+            "import dagger.multibindings.IntoMap;",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "public final class FooModule {",
+            "  @IntoMap",
+            "  @OuterKey(nestedKeys = @NestedKey)",
+            "  @Provides",
+            "  String provideString() { return \"hello\";}",
+            "}");
+    JavaFileObject component =
+        JavaFileObjects.forSourceLines(
+            "test.MyComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import java.util.Map;",
+            "",
+            "@Component(modules = FooModule.class)",
+            "public interface MyComponent {",
+            "  Map<OuterKey, String> getFoo();",
+            "}");
+    assertAbout(javaSources())
+        .that(ImmutableList.of(outerKey, nestedKey, foo, component))
+        .withCompilerOptions(compilerMode.javacopts())
+        .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+        .compilesWithoutError();
+  }
 }
diff --git a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java b/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
index 68564b2..6b9c526 100644
--- a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
@@ -88,7 +88,7 @@
             subject -> {
               subject.hasErrorCount(1);
               subject.hasErrorContaining(
-                      "The same map key is bound more than once for Map<String,Provider<Object>>")
+                      "The same map key is bound more than once for Map<String,Object>")
                   .onSource(module)
                   .onLineContaining("class MapModule");
               subject.hasErrorContaining("provideObjectForAKey()");
@@ -285,7 +285,7 @@
             subject -> {
               subject.hasErrorCount(1);
               subject.hasErrorContaining(
-                      "Map<String,Provider<Object>> uses more than one @MapKey annotation type")
+                      "Map<String,Object> uses more than one @MapKey annotation type")
                   .onSource(module)
                   .onLineContaining("class MapModule");
               subject.hasErrorContaining("provideObjectForAKey()");
@@ -374,6 +374,84 @@
             });
   }
 
+  @Test
+  public void mapBindingOfProvider_provides() {
+    Source providesModule =
+        CompilerTests.javaSource(
+            "test.MapModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.IntoMap;",
+            "import dagger.multibindings.StringKey;",
+            "import javax.inject.Provider;",
+            "",
+            "@Module",
+            "abstract class MapModule {",
+            "",
+            "  @Provides",
+            "  @IntoMap",
+            "  @StringKey(\"foo\")",
+            "  static Provider<String> provideProvider() {",
+            "    return null;",
+            "  }",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source providesComponent = component("");
+
+    CompilerTests.daggerCompiler(providesModule, providesComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Provides methods with @IntoMap must not return framework types");
+              subject.hasErrorContaining("test.MapModule has errors")
+                  .onSource(providesComponent)
+                  .onLineContaining("@Component(modules = {MapModule.class})");
+            });
+  }
+
+  @Test
+  public void mapBindingOfProvider_binds() {
+    Source bindsModule =
+        CompilerTests.javaSource(
+            "test.MapModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Binds;",
+            "import dagger.multibindings.IntoMap;",
+            "import dagger.multibindings.StringKey;",
+            "import javax.inject.Provider;",
+            "",
+            "@Module",
+            "abstract class MapModule {",
+            "",
+            "  @Binds",
+            "  @IntoMap",
+            "  @StringKey(\"foo\")",
+            "  abstract Provider<String> provideProvider(Provider<String> provider);",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source bindsComponent = component("");
+
+    CompilerTests.daggerCompiler(bindsModule, bindsComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Binds methods with @IntoMap must not return framework types");
+              subject.hasErrorContaining("test.MapModule has errors")
+                  .onSource(bindsComponent)
+                  .onLineContaining("@Component(modules = {MapModule.class})");
+            });
+  }
+
   private static Source component(String... entryPoints) {
     return CompilerTests.javaSource(
         "test.TestComponent",
diff --git a/javatests/dagger/internal/codegen/MembersInjectionTest.java b/javatests/dagger/internal/codegen/MembersInjectionTest.java
index 4748853..ee02f9f 100644
--- a/javatests/dagger/internal/codegen/MembersInjectionTest.java
+++ b/javatests/dagger/internal/codegen/MembersInjectionTest.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen;
 
+import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.util.Source;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -32,6 +33,23 @@
 
 @RunWith(Parameterized.class)
 public class MembersInjectionTest {
+
+  private static final Source TYPE_USE_NULLABLE =
+      CompilerTests.javaSource(
+          "test.Nullable", // force one-string-per-line format
+          "package test;",
+          "import static java.lang.annotation.ElementType.TYPE_USE;",
+          "import java.lang.annotation.Target;",
+          "",
+          "@Target(TYPE_USE)",
+          "public @interface Nullable {}");
+  private static final Source NON_TYPE_USE_NULLABLE =
+      CompilerTests.javaSource(
+          "test.Nullable", // force one-string-per-line format
+          "package test;",
+          "",
+          "public @interface Nullable {}");
+
   @Parameters(name = "{0}")
   public static ImmutableList<Object[]> parameters() {
     return CompilerMode.TEST_PARAMETERS;
@@ -329,6 +347,54 @@
   }
 
   @Test
+  public void typeUseNullableFieldInjection() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.FieldInjection",
+            "package test;",
+            "",
+            "import dagger.Lazy;",
+            "import javax.inject.Inject;",
+            "import javax.inject.Provider;",
+            "",
+            "class FieldInjection {",
+            "  @Inject @Nullable String string;",
+            "}");
+    CompilerTests.daggerCompiler(file, TYPE_USE_NULLABLE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  goldenFileRule.goldenSource("test/FieldInjection_MembersInjector"));
+            });
+  }
+
+  @Test
+  public void nonTypeUseNullableFieldInjection() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.FieldInjection",
+            "package test;",
+            "",
+            "import dagger.Lazy;",
+            "import javax.inject.Inject;",
+            "import javax.inject.Provider;",
+            "",
+            "class FieldInjection {",
+            "  @Inject @Nullable String string;",
+            "}");
+    CompilerTests.daggerCompiler(file, NON_TYPE_USE_NULLABLE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  goldenFileRule.goldenSource("test/FieldInjection_MembersInjector"));
+            });
+  }
+
+  @Test
   public void fieldInjectionWithQualifier() {
     Source file =
         CompilerTests.javaSource(
@@ -713,33 +779,6 @@
   }
 
   @Test
-  public void rawFrameworkTypeField() {
-    Source file =
-        CompilerTests.javaSource(
-            "test.RawFrameworkTypes",
-            "package test;",
-            "",
-            "import javax.inject.Inject;",
-            "import javax.inject.Provider;",
-            "",
-            "class RawProviderField {",
-            "  @Inject",
-            "  Provider fieldWithRawProvider;",
-            "}");
-
-    CompilerTests.daggerCompiler(file)
-        .withProcessingOptions(compilerMode.processorOptions())
-        .compile(
-            subject -> {
-              subject.hasErrorCount(1);
-              subject.hasErrorContaining(
-                      "Dagger does not support injecting raw type: javax.inject.Provider")
-                  .onSource(file)
-                  .onLineContaining("Provider fieldWithRawProvider");
-            });
-  }
-
-  @Test
   public void throwExceptionInjectedMethod() {
     Source file =
         CompilerTests.javaSource(
@@ -765,10 +804,37 @@
   }
 
   @Test
+  public void rawFrameworkTypeField() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.RawProviderField",
+            "package test;",
+            "",
+            "import javax.inject.Inject;",
+            "import javax.inject.Provider;",
+            "",
+            "class RawProviderField {",
+            "  @Inject",
+            "  Provider fieldWithRawProvider;",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger does not support injecting raw type: javax.inject.Provider")
+                  .onSource(file)
+                  .onLineContaining("Provider fieldWithRawProvider");
+            });
+  }
+
+  @Test
   public void rawFrameworkMethodTypeParameter() {
     Source file =
         CompilerTests.javaSource(
-            "test.RawFrameworkTypes",
+            "test.RawProviderParameter",
             "package test;",
             "",
             "import javax.inject.Inject;",
@@ -796,7 +862,7 @@
   public void rawFrameworkConstructorTypeParameter() {
     Source file =
         CompilerTests.javaSource(
-            "test.RawFrameworkTypes",
+            "test.RawProviderParameter",
             "package test;",
             "",
             "import dagger.Component;",
@@ -822,6 +888,274 @@
   }
 
   @Test
+  public void rawMapFrameworkConstructorTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.RawMapProviderParameter",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import javax.inject.Inject;",
+            "import javax.inject.Provider;",
+            "import java.util.Map;",
+            "",
+            "class RawMapProviderParameter {",
+            "  @Inject",
+            "  RawMapProviderParameter(",
+            "      Map<String, Provider> rawProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger does not support injecting maps of raw framework types: "
+                      + "java.util.Map<java.lang.String,javax.inject.Provider>")
+                  .onSource(file)
+                  .onLineContaining("Map<String, Provider> rawProviderParameter");
+            });
+  }
+
+  @Test
+  public void daggerProviderField() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerProviderField",
+            "package test;",
+            "",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "",
+            "class DaggerProviderField {",
+            "  @Inject",
+            "  Provider<String> fieldWithDaggerProvider;",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger disallows injecting the type: "
+                      + "dagger.internal.Provider<java.lang.String>")
+                  .onSource(file)
+                  .onLineContaining("Provider<String> fieldWithDaggerProvider");
+            });
+  }
+
+  @Test
+  public void daggerProviderMethodTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerProviderParameter",
+            "package test;",
+            "",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "",
+            "class DaggerProviderParameter {",
+            "  @Inject",
+            "  void methodInjection(",
+            "      Provider<String> daggerProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger disallows injecting the type: "
+                      + "dagger.internal.Provider<java.lang.String>")
+                  .onSource(file)
+                  .onLineContaining("Provider<String> daggerProviderParameter");
+            });
+  }
+
+  @Test
+  public void daggerProviderConstructorTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerProviderParameter",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "",
+            "class DaggerProviderParameter {",
+            "  @Inject",
+            "  DaggerProviderParameter(",
+            "      Provider<String> daggerProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger disallows injecting the type: "
+                      + "dagger.internal.Provider<java.lang.String>")
+                  .onSource(file)
+                  .onLineContaining("Provider<String> daggerProviderParameter");
+            });
+  }
+
+  @Test
+  public void rawDaggerProviderConstructorTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.RawDaggerProviderParameter",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "",
+            "class RawDaggerProviderParameter {",
+            "  @Inject",
+            "  RawDaggerProviderParameter(",
+            "      Provider rawDaggerProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger disallows injecting the type: dagger.internal.Provider")
+                  .onSource(file)
+                  .onLineContaining("Provider rawDaggerProviderParameter");
+            });
+  }
+
+  @Test
+  public void daggerMapProviderField() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerMapProviderField",
+            "package test;",
+            "",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "import java.util.Map;",
+            "",
+            "class DaggerMapProviderField {",
+            "  @Inject",
+            "  Map<String, Provider<Long>> fieldWithDaggerMapProvider;",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                      "Dagger does not support injecting maps of disallowed types: "
+                      + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
+                  .onSource(file)
+                  .onLineContaining("Map<String, Provider<Long>> fieldWithDaggerMapProvider");
+            });
+  }
+
+  @Test
+  public void daggerMapProviderMethodTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerMapProviderParameter",
+            "package test;",
+            "",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "import java.util.Map;",
+            "",
+            "class DaggerMapProviderParameter {",
+            "  @Inject",
+            "  void methodInjection(",
+            "      Map<String, Provider<Long>> daggerMapProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "Dagger does not support injecting maps of disallowed types: "
+                      + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
+                  .onSource(file)
+                  .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter");
+            });
+  }
+
+  @Test
+  public void daggerMapProviderConstructorTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.DaggerMapProviderParameter",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "import java.util.Map;",
+            "",
+            "class DaggerMapProviderParameter {",
+            "  @Inject",
+            "  DaggerMapProviderParameter(",
+            "      Map<String, Provider<Long>> daggerMapProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "Dagger does not support injecting maps of disallowed types: "
+                  + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>")
+                  .onSource(file)
+                  .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter");
+            });
+  }
+
+  @Test
+  public void rawDaggerMapProviderConstructorTypeParameter() {
+    Source file =
+        CompilerTests.javaSource(
+            "test.RawDaggerMapProviderParameter",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import dagger.internal.Provider;",
+            "import javax.inject.Inject;",
+            "import java.util.Map;",
+            "",
+            "class RawDaggerMapProviderParameter {",
+            "  @Inject",
+            "  RawDaggerMapProviderParameter(",
+            "      Map<String, Provider> rawDaggerMapProviderParameter) {}",
+            "}");
+
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "Dagger does not support injecting maps of disallowed types: "
+                  + "java.util.Map<java.lang.String,dagger.internal.Provider>")
+                  .onSource(file)
+                  .onLineContaining("Map<String, Provider> rawDaggerMapProviderParameter");
+            });
+  }
+
+  @Test
   public void injectsPrimitive() throws Exception {
     Source injectedType =
         CompilerTests.javaSource(
@@ -1271,4 +1605,71 @@
               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent"));
             });
   }
+
+  @Test
+  public void kotlinNullableFieldInjection() {
+    Source file =
+        CompilerTests.kotlinSource(
+            "MyClass.kt",
+            "package test;",
+            "",
+            "import javax.inject.Inject;",
+            "",
+            "class MyClass @Inject constructor() {",
+            "  @JvmField @Inject var nullableString: String? = null",
+            "  @JvmField @Inject var nullableObject: Any? = null",
+            "}");
+    CompilerTests.daggerCompiler(file)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              Source expectedSource = goldenFileRule.goldenSource("test/MyClass_MembersInjector");
+              subject.generatedSource(
+                  CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
+                      ? stripJetbrainsNullable(expectedSource)
+                      : expectedSource);
+            });
+  }
+
+  @Test
+  public void testMembersInjectionBindingWithNoInjectionSites() throws Exception {
+    Source component =
+        CompilerTests.javaSource(
+            "test.MyComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "",
+            "@Component",
+            "public interface MyComponent {",
+            "  void inject(Foo foo);",
+            "",
+            "  Foo injectAndReturn(Foo foo);",
+            "}");
+
+    Source foo =
+        CompilerTests.javaSource(
+            "test.Foo",
+            "package test;",
+            "",
+            "class Foo {}");
+
+    CompilerTests.daggerCompiler(component, foo)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent"));
+            });
+  }
+
+  private Source stripJetbrainsNullable(Source source) {
+    return CompilerTests.javaSource(
+        ((Source.JavaSource) source).getQName(),
+        source
+            .getContents()
+            .replace("@Nullable ", "")
+            .replace("import org.jetbrains.annotations.Nullable;\n", ""));
+  }
 }
diff --git a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
index 8250861..4910011 100644
--- a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
@@ -32,6 +32,10 @@
 
 @RunWith(Parameterized.class)
 public class MissingBindingValidationTest {
+  private static final String JVM_SUPPRESS_WILDCARDS_MESSAGE =
+      "(For Kotlin sources, you may need to use '@JvmSuppressWildcards' or '@JvmWildcard' if you "
+          + "need to explicitly control the wildcards at a particular usage site.)";
+
   @Parameters(name = "{0}")
   public static ImmutableList<Object[]> parameters() {
     return CompilerMode.TEST_PARAMETERS;
@@ -1097,7 +1101,9 @@
                       "        [Child1] Child1.getObject() [Parent → Child1]",
                       "",
                       "Note: Object is provided in the following other components:",
-                      "    [Child2] Child2Module.provideObject()"));
+                      "    [Child2] Child2Module.provideObject()",
+                      "",
+                      "======================"));
             });
   }
 
@@ -1218,7 +1224,9 @@
                           + "[Parent → Child1 → RepeatedSub]",
                       "",
                       "Note: Object is provided in the following other components:",
-                      "    [Child2] Child2Module.provideObject(…)"));
+                      "    [Child2] Child2Module.provideObject(…)",
+                      "",
+                      "======================"));
             });
   }
 
@@ -1349,7 +1357,9 @@
                       "        [Sub] Sub.getObject() [Parent → Child1 → Sub]",
                       "",
                       "Note: Object is provided in the following other components:",
-                      "    [Child2] Child2Module.provideObject(…)"));
+                      "    [Child2] Child2Module.provideObject(…)",
+                      "",
+                      "======================"));
             });
   }
 
@@ -1449,7 +1459,10 @@
                           "",
                           "Note: A similar binding is provided in the following other components:",
                           "    Set<Bar> is provided at:",
-                          "        [MyComponent] Dagger-generated binding for Set<Bar>"))
+                          "        [MyComponent] Dagger-generated binding for Set<Bar>",
+                          JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                          "",
+                          "======================"))
                   .onSource(component)
                   .onLineContaining("interface MyComponent");
             });
@@ -1519,7 +1532,10 @@
                           "",
                           "Note: A similar binding is provided in the following other components:",
                           "    Set<Bar> is provided at:",
-                          "        [MyComponent] Dagger-generated binding for Set<Bar>"))
+                          "        [MyComponent] Dagger-generated binding for Set<Bar>",
+                          JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                          "",
+                          "======================"))
                   .onSource(component)
                   .onLineContaining("interface MyComponent");
             });
@@ -1592,7 +1608,10 @@
                           "",
                           "Note: A similar binding is provided in the following other components:",
                           "    Set<Bar> is provided at:",
-                          "        [MyComponent] Dagger-generated binding for Set<Bar>"))
+                          "        [MyComponent] Dagger-generated binding for Set<Bar>",
+                          JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                          "",
+                          "======================"))
                   .onSource(component)
                   .onLineContaining("interface MyComponent");
             });
@@ -1654,7 +1673,10 @@
                           "",
                           "Note: A similar binding is provided in the following other components:",
                           "    List<? extends Bar> is provided at:",
-                          "        [MyComponent] TestModule.provideBars()"))
+                          "        [MyComponent] TestModule.provideBars()",
+                          JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                          "",
+                          "======================"))
                   .onSource(component)
                   .onLineContaining("interface MyComponent");
             });
@@ -1729,7 +1751,10 @@
                           "",
                           "Note: A similar binding is provided in the following other components:",
                           "    Bar<Baz,Baz,Set<Baz>> is provided at:",
-                          "        [MyComponent] TestModule.provideBar()"))
+                          "        [MyComponent] TestModule.provideBar()",
+                          JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                          "",
+                          "======================"))
                   .onSource(component)
                   .onLineContaining("interface MyComponent");
             });
@@ -1865,7 +1890,10 @@
                       "",
                       "Note: A similar binding is provided in the following other components:",
                       "    Bar is provided at:",
-                      "        [MyComponent] TestModule.provideBar()"));
+                      "        [MyComponent] TestModule.provideBar()",
+                      JVM_SUPPRESS_WILDCARDS_MESSAGE,
+                      "",
+                      "======================"));
             });
   }
 
@@ -1923,4 +1951,218 @@
                   .doesNotContain("bindings with similar types exists in the graph");
             });
   }
+
+  // Regression test for b/367426609
+  @Test
+  public void failsWithMissingBindingInGrandchild() {
+    Source parent =
+        CompilerTests.javaSource(
+            "test.Parent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "",
+            "@Component(modules = ParentModule.class)",
+            "interface Parent {",
+            "  Child child();",
+            "}");
+    Source child =
+        CompilerTests.javaSource(
+            "test.Child",
+            "package test;",
+            "",
+            "import dagger.Subcomponent;",
+            "",
+            "@Subcomponent(modules = ChildModule.class)",
+            "interface Child {",
+            "  Grandchild grandchild();",
+            "}");
+    Source grandchild =
+        CompilerTests.javaSource(
+            "test.Grandchild",
+            "package test;",
+            "",
+            "import dagger.Subcomponent;",
+            "",
+            "@Subcomponent(modules=GrandchildModule.class)",
+            "interface Grandchild {",
+            // Note: it's important that Qux is first to reproduce the error in b/367426609.
+            "  Qux getQux();",
+            "  Foo getFoo();",
+            "}");
+    Source parentModule =
+        CompilerTests.javaSource(
+            "test.ParentModule",
+            "package test;",
+            "",
+            "import dagger.BindsOptionalOf;",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import java.util.Optional;",
+            "",
+            "@Module",
+            "interface ParentModule {",
+            "  @BindsOptionalOf",
+            "  String optionalString();",
+            "",
+            // depend on an @BindsOptionalOf to force re-resolution in subcomponents.
+            "  @Provides",
+            "  static Foo provideFoo(Optional<String> str, Qux qux) { return null; }",
+            "}");
+    Source childModule =
+        CompilerTests.javaSource(
+            "test.ChildModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "interface ChildModule {",
+            "  @Provides",
+            "  static Qux provideQux() { return null; }",
+            "}");
+    Source grandchildModule =
+        CompilerTests.javaSource(
+            "test.GrandchildModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "interface GrandchildModule {",
+            "  @Provides",
+            "  static String provideString() { return null; }",
+            "}");
+    Source foo =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Foo",
+            "package test;",
+            "",
+            "interface Foo {}");
+    Source bar =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Bar",
+            "package test;",
+            "",
+            "interface Bar {}");
+    Source qux =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Qux",
+            "package test;",
+            "",
+            "interface Qux {}");
+
+    CompilerTests.daggerCompiler(
+            parent, child, grandchild, parentModule, childModule, grandchildModule, foo, bar, qux)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(subject -> subject.hasErrorCount(0));
+  }
+
+  // Regression test for b/367426609
+  @Test
+  public void failsWithMissingBindingInGrandchild_dependencyTracePresent() {
+    Source parent =
+        CompilerTests.javaSource(
+            "test.Parent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "",
+            "@Component(modules = ParentModule.class)",
+            "interface Parent {",
+            "  Child child();",
+            "}");
+    Source child =
+        CompilerTests.javaSource(
+            "test.Child",
+            "package test;",
+            "",
+            "import dagger.Subcomponent;",
+            "",
+            "@Subcomponent(modules = ChildModule.class)",
+            "interface Child {",
+            "  Grandchild grandchild();",
+            "}");
+    Source grandchild =
+        CompilerTests.javaSource(
+            "test.Grandchild",
+            "package test;",
+            "",
+            "import dagger.Subcomponent;",
+            "",
+            "@Subcomponent(modules=GrandchildModule.class)",
+            "interface Grandchild {",
+            "  Foo getFoo();",
+            "}");
+    Source parentModule =
+        CompilerTests.javaSource(
+            "test.ParentModule",
+            "package test;",
+            "",
+            "import dagger.BindsOptionalOf;",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import java.util.Optional;",
+            "",
+            "@Module",
+            "interface ParentModule {",
+            "  @BindsOptionalOf",
+            "  String optionalString();",
+            "",
+            // depend on an @BindsOptionalOf to force re-resolution in subcomponents.
+            "  @Provides",
+            "  static Foo provideFoo(Optional<String> str, Qux qux) { return null; }",
+            "}");
+    Source childModule =
+        CompilerTests.javaSource(
+            "test.ChildModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "interface ChildModule {",
+            "  @Provides",
+            "  static Qux provideQux() { return null; }",
+            "}");
+    Source grandchildModule =
+        CompilerTests.javaSource(
+            "test.GrandchildModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "interface GrandchildModule {",
+            "  @Provides",
+            "  static String provideString() { return null; }",
+            "}");
+    Source foo =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Foo",
+            "package test;",
+            "",
+            "interface Foo {}");
+    Source bar =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Bar",
+            "package test;",
+            "",
+            "interface Bar {}");
+    Source qux =
+        CompilerTests.javaSource( // force one-string-per-line format
+            "test.Qux",
+            "package test;",
+            "",
+            "interface Qux {}");
+
+    CompilerTests.daggerCompiler(
+            parent, child, grandchild, parentModule, childModule, grandchildModule, foo, bar, qux)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(subject -> subject.hasErrorCount(0));
+  }
 }
diff --git a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
index cc8e3b4..ccff741 100644
--- a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -19,6 +19,7 @@
 import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
 import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
 
+import androidx.room.compiler.processing.XProcessingEnv;
 import androidx.room.compiler.processing.util.Source;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -32,9 +33,12 @@
 @RunWith(JUnit4.class)
 public class ModuleFactoryGeneratorTest {
 
-  private static final Source NULLABLE =
-        CompilerTests.javaSource(
-          "test.Nullable", "package test;", "public @interface Nullable {}");
+  private static final Source NON_TYPE_USE_NULLABLE =
+      CompilerTests.javaSource(
+          "test.Nullable", // force one-string-per-line format
+          "package test;",
+          "",
+          "public @interface Nullable {}");
 
   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
 
@@ -68,6 +72,25 @@
   }
 
   @Test
+  public void providesMethodReturnsJakartaProvider() {
+    assertThatModuleMethod("@Provides jakarta.inject.Provider<String> provideProvider() {}")
+        .hasError("@Provides methods must not return framework types");
+  }
+
+  @Test
+  public void providesMethodReturnsDaggerInternalProvider() {
+    assertThatModuleMethod("@Provides dagger.internal.Provider<String> provideProvider() {}")
+        .hasError("@Provides methods must not return disallowed types");
+  }
+
+  @Test
+  public void providesIntoSetMethodReturnsDaggerInternalProvider() {
+    assertThatModuleMethod(
+        "@Provides @IntoSet dagger.internal.Provider<String> provideProvider() {}")
+        .hasError("@Provides methods must not return disallowed types");
+  }
+
+  @Test
   public void providesMethodReturnsLazy() {
     assertThatModuleMethod("@Provides Lazy<String> provideLazy() {}")
         .hasError("@Provides methods must not return framework types");
@@ -108,12 +131,31 @@
         .hasError("@Provides methods annotated with @ElementsIntoSet cannot return a raw Set");
   }
 
+  @Test public void providesElementsIntoSetMethodReturnsSetDaggerProvider() {
+    assertThatModuleMethod(
+        "@Provides @ElementsIntoSet Set<dagger.internal.Provider<String>> provideProvider() {}")
+        .hasError("@Provides methods must not return disallowed types");
+  }
+
   @Test public void providesMethodSetValuesNotASet() {
     assertThatModuleMethod(
             "@Provides @ElementsIntoSet List<String> provideStrings() { return null; }")
         .hasError("@Provides methods annotated with @ElementsIntoSet must return a Set");
   }
 
+  @Test
+  public void bindsMethodReturnsProvider() {
+    assertThatModuleMethod("@Binds abstract Provider<Number> bindsProvider(Provider<Long> impl);")
+        .hasError("@Binds methods must not return framework types");
+  }
+
+  @Test
+  public void bindsMethodReturnsDaggerProvider() {
+    assertThatModuleMethod("@Binds abstract dagger.internal.Provider<Number> "
+        + "bindsProvider(dagger.internal.Provider<Long> impl);")
+        .hasError("@Binds methods must not return disallowed types");
+  }
+
   @Test public void modulesWithTypeParamsMustBeAbstract() {
     Source moduleFile =
         CompilerTests.javaSource(
@@ -277,7 +319,8 @@
             });
   }
 
-  @Test public void nullableProvides() {
+  @Test
+  public void nonTypeUseNullableProvides() {
     Source moduleFile =
         CompilerTests.javaSource(
             "test.TestModule",
@@ -290,7 +333,7 @@
             "final class TestModule {",
             "  @Provides @Nullable String provideString() { return null; }",
             "}");
-    CompilerTests.daggerCompiler(moduleFile, NULLABLE)
+    CompilerTests.daggerCompiler(moduleFile, NON_TYPE_USE_NULLABLE)
         .compile(
             subject -> {
               subject.hasErrorCount(0);
@@ -299,6 +342,80 @@
             });
   }
 
+  @Test
+  public void kotlinNullableProvides() {
+    Source moduleFile =
+        CompilerTests.kotlinSource(
+            "TestModule.kt",
+            "package test",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "",
+            "@Module",
+            "class TestModule {",
+            "  @Provides fun provideString(): String? { return null; }",
+            "}");
+    CompilerTests.daggerCompiler(moduleFile)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(0);
+              boolean isJavac = CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC;
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test.TestModule_ProvideStringFactory",
+                      "package test;",
+                      "",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import dagger.internal.Factory;",
+                      "import dagger.internal.QualifierMetadata;",
+                      "import dagger.internal.ScopeMetadata;",
+                      "import javax.annotation.processing.Generated;",
+                      isJavac ? "import org.jetbrains.annotations.Nullable;\n" : "",
+                      "@ScopeMetadata",
+                      "@QualifierMetadata",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class TestModule_ProvideStringFactory implements"
+                          + " Factory<String> {",
+                      "  private final TestModule module;",
+                      "",
+                      "  public TestModule_ProvideStringFactory(TestModule module) {",
+                      "    this.module = module;",
+                      "  }",
+                      "",
+                      // TODO(b/368129744): KSP should output the @Nullable annotation after this
+                      // bug is fixed.
+                      isJavac ? "  @Override\n  @Nullable" : "  @Override",
+                      "  public String get() {",
+                      "    return provideString(module);",
+                      "  }",
+                      "",
+                      "  public static TestModule_ProvideStringFactory create(TestModule module) {",
+                      "    return new TestModule_ProvideStringFactory(module);",
+                      "  }",
+                      // TODO(b/368129744): KSP should output the @Nullable annotation after this
+                      // bug is fixed.
+                      isJavac ? "\n  @Nullable" : "",
+                      "  public static String provideString(TestModule instance) {",
+                      "    return instance.provideString();",
+                      "  }",
+                      "}"));
+            });
+  }
+
   @Test public void multipleProvidesMethods() {
     Source classXFile =
         CompilerTests.javaSource("test.X",
@@ -344,7 +461,8 @@
             });
   }
 
-  @Test public void providesSetElement() {
+  @Test
+  public void providesSetElement() {
     Source moduleFile =
         CompilerTests.javaSource(
             "test.TestModule",
diff --git a/javatests/dagger/internal/codegen/MultibindingTest.java b/javatests/dagger/internal/codegen/MultibindingTest.java
index 119fe80..e9b403f 100644
--- a/javatests/dagger/internal/codegen/MultibindingTest.java
+++ b/javatests/dagger/internal/codegen/MultibindingTest.java
@@ -24,6 +24,39 @@
 
 @RunWith(JUnit4.class)
 public class MultibindingTest {
+  @Test
+  public void multibindingContributedWithKotlinProperty_compilesSucessfully() {
+    Source component =
+        CompilerTests.javaSource(
+            "test.MyComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import java.util.Set;",
+            "",
+            "@Component(modules = TestModule.class)",
+            "interface MyComponent {",
+            "  Set<String> getStrs();",
+            "}");
+    Source moduleSrc =
+        CompilerTests.kotlinSource(
+            "test.TestModule.kt",
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoSet",
+            "",
+            "@Module",
+            "object TestModule {",
+            "@get:IntoSet",
+            "@get:Provides",
+            "val helloString: String",
+            "  get() = \"hello\"",
+            "}");
+
+    CompilerTests.daggerCompiler(component, moduleSrc).compile(subject -> subject.hasErrorCount(0));
+  }
 
   @Test
   public void providesWithTwoMultibindingAnnotations_failsToCompile() {
@@ -266,4 +299,341 @@
                   .onLineContaining("interface Parent");
             });
   }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingMapWithKotlinSource() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "",
+            "class Usage @Inject constructor(map: Map<String, MyInterface>)");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoMap",
+            "import dagger.multibindings.StringKey",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @StringKey(\"key\")",
+            "  fun provideMyInterface(): MyInterface = TODO()",
+            "}");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("Map<String,? extends MyInterface> cannot be provided");
+            });
+  }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingMapWithOutVarianceKotlinSource_succeeds() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "",
+            "class Usage @Inject constructor(",
+            "  map: Map<String, @JvmSuppressWildcards MyGenericInterface<out MyInterface>>",
+            ")");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoMap",
+            "import dagger.multibindings.StringKey",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @StringKey(\"key\")",
+            "  fun provideMyInterface(): MyGenericInterface<out MyInterface> = TODO()",
+            "}");
+    Source myGenericInterface =
+        CompilerTests.kotlinSource(
+            "test.MyGenericInterface.kt",
+            "package test",
+            "",
+            "interface MyGenericInterface<T>");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myGenericInterface, myInterface, usage)
+        .compile(subject -> subject.hasErrorCount(0));
+  }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingMapWithJvmWildcardsKotlinSource_succeeds() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "",
+            "class Usage @Inject constructor(",
+            "  map: Map<String,@JvmSuppressWildcards MyGenericInterface<@JvmWildcard MyInterface>>",
+            ")");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoMap",
+            "import dagger.multibindings.StringKey",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @StringKey(\"key\")",
+            "  fun provideMyInterface(): MyGenericInterface<@JvmWildcard MyInterface> = TODO()",
+            "}");
+    Source myGenericInterface =
+        CompilerTests.kotlinSource(
+            "test.MyGenericInterface.kt",
+            "package test",
+            "",
+            "interface MyGenericInterface<out T>");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myGenericInterface, myInterface, usage)
+        .compile(subject -> subject.hasErrorCount(0));
+  }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingMapProviderWithKotlinSource() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "import javax.inject.Provider",
+            "",
+            "class Usage @Inject constructor(map: Map<String, Provider<MyInterface>>)");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoMap",
+            "import dagger.multibindings.StringKey",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoMap",
+            "  @StringKey(\"key\")",
+            "  fun provideMyInterface(): MyInterface = TODO()",
+            "}");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "Map<String,? extends Provider<MyInterface>> cannot be provided");
+            });
+  }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingSetWithKotlinSource() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "",
+            "class Usage @Inject constructor(set: Set<MyInterface>)");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoSet",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoSet",
+            "  fun provideMyInterface(): MyInterface = TODO()",
+            "}");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("Set<? extends MyInterface> cannot be provided");
+            });
+  }
+
+  // Regression test for b/352142595.
+  @Test
+  public void testMultibindingSetProviderWithKotlinSource() {
+    Source parent =
+        CompilerTests.kotlinSource(
+            "test.Parent.kt",
+            "package test",
+            "",
+            "import dagger.Component",
+            "",
+            "@Component(modules = [ParentModule::class])",
+            "interface Parent {",
+            "  fun usage(): Usage",
+            "}");
+    Source usage =
+        CompilerTests.kotlinSource(
+            "test.Usage.kt",
+            "package test",
+            "",
+            "import javax.inject.Inject",
+            "import javax.inject.Provider",
+            "",
+            "class Usage @Inject constructor(set: Set<Provider<MyInterface>>)");
+    Source parentModule =
+        CompilerTests.kotlinSource(
+            "test.ParentModule.kt",
+            "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
+            "package test",
+            "",
+            "import dagger.Module",
+            "import dagger.Provides",
+            "import dagger.multibindings.IntoSet",
+            "",
+            "@Module",
+            "class ParentModule {",
+            "  @Provides",
+            "  @IntoSet",
+            "  fun provideMyInterface(): MyInterface = TODO()",
+            "}");
+    Source myInterface =
+        CompilerTests.kotlinSource(
+            "test.MyInterface.kt",
+            "package test",
+            "",
+            "interface MyInterface");
+
+    CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("Set<? extends Provider<MyInterface>> cannot be provided");
+            });
+  }
 }
diff --git a/javatests/dagger/internal/codegen/MultibindsValidationTest.java b/javatests/dagger/internal/codegen/MultibindsValidationTest.java
index a006dfa..0395c70 100644
--- a/javatests/dagger/internal/codegen/MultibindsValidationTest.java
+++ b/javatests/dagger/internal/codegen/MultibindsValidationTest.java
@@ -142,20 +142,6 @@
   }
 
   @Test
-  public void providerSet() {
-    assertThatModuleMethod("@Multibinds abstract Set<Provider<Object>> providerSet();")
-        .withDeclaration(moduleDeclaration)
-        .hasError("return type cannot use 'Provider' in the Set value type.");
-  }
-
-  @Test
-  public void producerSet() {
-    assertThatModuleMethod("@Multibinds abstract Set<Producer<Object>> producerSet();")
-        .withDeclaration(moduleDeclaration)
-        .hasError("return type cannot use 'Producer' in the Set value type.");
-  }
-
-  @Test
   public void producedSet() {
     assertThatModuleMethod("@Multibinds abstract Set<Produced<Object>> producedSet();")
         .withDeclaration(moduleDeclaration)
diff --git a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
index 188f4d6..d01b694 100644
--- a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
@@ -23,7 +23,6 @@
 import com.google.testing.compile.Compilation;
 import com.google.testing.compile.JavaFileObjects;
 import dagger.testing.golden.GoldenFileRule;
-import java.util.Collection;
 import javax.tools.JavaFileObject;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,14 +33,8 @@
 @RunWith(Parameterized.class)
 public class OptionalBindingRequestFulfillmentTest {
   @Parameters(name = "{0}")
-  public static Collection<Object[]> parameters() {
-    return ImmutableList.copyOf(
-        new Object[][] {
-            {CompilerMode.DEFAULT_MODE},
-            {CompilerMode.DEFAULT_JAVA7_MODE},
-            {CompilerMode.FAST_INIT_MODE},
-            {CompilerMode.FAST_INIT_JAVA7_MODE}
-        });
+  public static ImmutableList<Object[]> parameters() {
+    return CompilerMode.TEST_PARAMETERS;
   }
 
   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
diff --git a/javatests/dagger/internal/codegen/OptionalBindingTest.java b/javatests/dagger/internal/codegen/OptionalBindingTest.java
index bcec73f..76a0592 100644
--- a/javatests/dagger/internal/codegen/OptionalBindingTest.java
+++ b/javatests/dagger/internal/codegen/OptionalBindingTest.java
@@ -105,4 +105,74 @@
                   .onLineContaining("interface Parent");
             });
   }
+
+  // Note: This is a regression test for an issue we ran into in CL/644086367, where an optional
+  // binding owned by a parent component is also requested by a child component which declares an
+  // additional @BindsOptionalOf declaration. In this case, we just want to make sure that the setup
+  // builds successfully.
+  @Test
+  public void cachedInParent_succeeds() {
+    Source parent =
+        CompilerTests.javaSource(
+            "test.Parent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "import java.util.Optional;",
+            "",
+            "@Component(modules = ParentModule.class)",
+            "interface Parent {",
+            "  Optional<String> optionalString();",
+            "  Child child();",
+            "}");
+    Source parentModule =
+        CompilerTests.javaSource(
+            "test.ParentModule",
+            "package test;",
+            "",
+            "import dagger.BindsOptionalOf;",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import java.util.Optional;",
+            "",
+            "@Module",
+            "interface ParentModule {",
+            "  @BindsOptionalOf",
+            "  String optionalParentString();",
+            "",
+            "  @Provides",
+            "  static String provideString() {",
+            "    return \"\";",
+            "  }",
+            "}");
+    Source child =
+        CompilerTests.javaSource(
+            "test.Child",
+            "package test;",
+            "",
+            "import dagger.Subcomponent;",
+            "import java.util.Optional;",
+            "",
+            "@Subcomponent(modules = ChildModule.class)",
+            "interface Child {",
+            "  Optional<String> optionalString();",
+            "}");
+    Source childModule =
+        CompilerTests.javaSource(
+            "test.ChildModule",
+            "package test;",
+            "",
+            "import dagger.BindsOptionalOf;",
+            "import dagger.Module;",
+            "",
+            "@Module",
+            "interface ChildModule {",
+            "  @BindsOptionalOf",
+            "  String optionalChildString();",
+            "}");
+
+    CompilerTests.daggerCompiler(parent, parentModule, child, childModule)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(subject -> subject.hasErrorCount(0));
+  }
 }
diff --git a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
index 39e63c9..6840aad 100644
--- a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
@@ -16,6 +16,7 @@
 
 package dagger.internal.codegen;
 
+
 import androidx.room.compiler.processing.util.Source;
 import com.google.common.collect.ImmutableMap;
 import dagger.testing.compile.CompilerTests;
@@ -34,6 +35,24 @@
     return CompilerMode.TEST_PARAMETERS;
   }
 
+  private static final Source EXECUTOR_MODULE =
+      CompilerTests.javaSource(
+          "test.ExecutorModule",
+          "package test;",
+          "",
+          "import com.google.common.util.concurrent.MoreExecutors;",
+          "import dagger.Module;",
+          "import dagger.Provides;",
+          "import dagger.producers.Production;",
+          "import java.util.concurrent.Executor;",
+          "",
+          "@Module",
+          "final class ExecutorModule {",
+          "  @Provides @Production Executor executor() {",
+          "    return MoreExecutors.directExecutor();",
+          "  }",
+          "}");
+
   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
 
   private final CompilerMode compilerMode;
@@ -121,23 +140,6 @@
 
   @Test
   public void dependsOnProductionExecutor() throws Exception {
-    Source moduleFile =
-        CompilerTests.javaSource(
-            "test.ExecutorModule",
-            "package test;",
-            "",
-            "import com.google.common.util.concurrent.MoreExecutors;",
-            "import dagger.Module;",
-            "import dagger.Provides;",
-            "import dagger.producers.Production;",
-            "import java.util.concurrent.Executor;",
-            "",
-            "@Module",
-            "final class ExecutorModule {",
-            "  @Provides @Production Executor executor() {",
-            "    return MoreExecutors.directExecutor();",
-            "  }",
-            "}");
     Source producerModuleFile =
         CompilerTests.javaSource(
             "test.SimpleModule",
@@ -174,7 +176,7 @@
             "}");
 
     String errorMessage = "String may not depend on the production executor";
-    CompilerTests.daggerCompiler(moduleFile, producerModuleFile, componentFile)
+    CompilerTests.daggerCompiler(EXECUTOR_MODULE, producerModuleFile, componentFile)
         .withProcessingOptions(compilerMode.processorOptions())
         .compile(
             subject -> {
@@ -415,4 +417,223 @@
               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent"));
             });
   }
+
+  @Test
+  public void requestProducerNodeWithProvider_failsWithNotSupportedError() {
+    Source producerModuleFile =
+        CompilerTests.javaSource(
+            "test.SimpleModule",
+            "package test;",
+            "",
+            "import dagger.producers.ProducerModule;",
+            "import dagger.producers.Produces;",
+            "import javax.inject.Provider;",
+            "import java.util.concurrent.Executor;",
+            "import dagger.producers.Production;",
+            "",
+            "@ProducerModule",
+            "final class SimpleModule {",
+            "  @Produces String str(Provider<Integer> num) {",
+            "    return \"\";",
+            "  }",
+            "  @Produces Integer num() { return 1; }",
+            "}");
+    Source componentFile =
+        CompilerTests.javaSource(
+            "test.SimpleComponent",
+            "package test;",
+            "",
+            "import com.google.common.util.concurrent.ListenableFuture;",
+            "import dagger.producers.ProductionComponent;",
+            "",
+            "@ProductionComponent(modules = {ExecutorModule.class, SimpleModule.class})",
+            "interface SimpleComponent {",
+            "  ListenableFuture<String> str();",
+            "",
+            "  @ProductionComponent.Builder",
+            "  interface Builder {",
+            "    SimpleComponent build();",
+            "  }",
+            "}");
+
+    CompilerTests.daggerCompiler(EXECUTOR_MODULE, producerModuleFile, componentFile)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "request kind PROVIDER cannot be satisfied by production binding");
+            });
+  }
+
+  @Test
+  public void productionBindingKind_failsIfScoped() {
+    Source component =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import com.google.common.util.concurrent.ListenableFuture;",
+            "import dagger.producers.ProductionComponent;",
+            "",
+            "@ProductionComponent(modules = {ExecutorModule.class, TestModule.class})",
+            "interface TestComponent {",
+            "  ListenableFuture<String> str();",
+            "}");
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestModule",
+            "package test;",
+            "",
+            "import dagger.producers.ProducerModule;",
+            "import dagger.producers.Produces;",
+            "import dagger.producers.ProductionScope;",
+            "import javax.inject.Provider;",
+            "import java.util.concurrent.Executor;",
+            "import dagger.producers.Production;",
+            "",
+            "@ProducerModule",
+            "interface TestModule {",
+            "  @ProductionScope",
+            "  @Produces",
+            "  static String provideString() { return \"\"; }",
+            "}");
+
+    CompilerTests.daggerCompiler(component, module, EXECUTOR_MODULE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining("@Produces methods cannot be scoped");
+            });
+  }
+
+  @Test
+  public void delegateToProductionBindingKind_failsIfScoped() {
+    Source component =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import com.google.common.util.concurrent.ListenableFuture;",
+            "import dagger.producers.ProductionComponent;",
+            "",
+            "@ProductionComponent(modules = {ExecutorModule.class, TestModule.class})",
+            "interface TestComponent {",
+            "  ListenableFuture<Foo> foo();",
+            "}");
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestModule",
+            "package test;",
+            "",
+            "import dagger.Binds;",
+            "import dagger.producers.ProducerModule;",
+            "import dagger.producers.Produces;",
+            "import dagger.producers.ProductionScope;",
+            "import javax.inject.Provider;",
+            "import java.util.concurrent.Executor;",
+            "import dagger.producers.Production;",
+            "",
+            "@ProducerModule",
+            "interface TestModule {",
+            "  @ProductionScope",
+            "  @Binds",
+            "  Foo bind(FooImpl impl);",
+            "",
+            "  @Produces",
+            "  static FooImpl fooImpl() { return new FooImpl(); }",
+            "}");
+    Source foo =
+        CompilerTests.javaSource(
+            "test.Foo",
+            "package test;",
+            "",
+            "interface Foo {}");
+    Source fooImpl =
+        CompilerTests.javaSource(
+            "test.FooImpl",
+            "package test;",
+            "",
+            "final class FooImpl implements Foo {}");
+
+    CompilerTests.daggerCompiler(component, module, foo, fooImpl, EXECUTOR_MODULE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "@ProductionScope @Binds Foo TestModule.bind(FooImpl) cannot be scoped "
+                      + "because it delegates to an @Produces method");
+            });
+  }
+
+  @Test
+  public void multipleDelegatesToProductionBindingKind_failsIfScoped() {
+    Source component =
+        CompilerTests.javaSource(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import com.google.common.util.concurrent.ListenableFuture;",
+            "import dagger.producers.ProductionComponent;",
+            "",
+            "@ProductionComponent(modules = {ExecutorModule.class, TestModule.class})",
+            "interface TestComponent {",
+            "  ListenableFuture<FooSuper> fooSuper();",
+            "}");
+    Source module =
+        CompilerTests.javaSource(
+            "test.TestModule",
+            "package test;",
+            "",
+            "import dagger.Binds;",
+            "import dagger.producers.ProducerModule;",
+            "import dagger.producers.Produces;",
+            "import dagger.producers.ProductionScope;",
+            "import javax.inject.Provider;",
+            "import java.util.concurrent.Executor;",
+            "import dagger.producers.Production;",
+            "",
+            "@ProducerModule",
+            "interface TestModule {",
+            "  @ProductionScope",
+            "  @Binds",
+            "  FooSuper bindFooSuper(Foo impl);",
+            "",
+            "  @Binds",
+            "  Foo bindFoo(FooImpl impl);",
+            "",
+            "  @Produces",
+            "  static FooImpl fooImpl() { return new FooImpl(); }",
+            "}");
+    Source fooSuper =
+        CompilerTests.javaSource(
+            "test.FooSuper",
+            "package test;",
+            "",
+            "interface FooSuper {}");
+    Source foo =
+        CompilerTests.javaSource(
+            "test.Foo",
+            "package test;",
+            "",
+            "interface Foo extends FooSuper {}");
+    Source fooImpl =
+        CompilerTests.javaSource(
+            "test.FooImpl",
+            "package test;",
+            "",
+            "final class FooImpl implements Foo {}");
+
+    CompilerTests.daggerCompiler(component, module, fooSuper, foo, fooImpl, EXECUTOR_MODULE)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(1);
+              subject.hasErrorContaining(
+                  "@ProductionScope @Binds FooSuper TestModule.bindFooSuper(Foo) cannot be scoped "
+                      + "because it delegates to an @Produces method");
+            });
+  }
 }
diff --git a/javatests/dagger/internal/codegen/ScopingValidationTest.java b/javatests/dagger/internal/codegen/ScopingValidationTest.java
index fe112a2..4d811b9 100644
--- a/javatests/dagger/internal/codegen/ScopingValidationTest.java
+++ b/javatests/dagger/internal/codegen/ScopingValidationTest.java
@@ -78,7 +78,7 @@
                       "MyComponent (unscoped) may not reference scoped bindings:",
                       "    @Singleton class ScopedType",
                       "    ScopedType is requested at",
-                      "        MyComponent.string()",
+                      "        [MyComponent] MyComponent.string()",
                       "",
                       "    @Provides @Singleton String ScopedModule.string()"));
             });
@@ -242,7 +242,7 @@
                               + "different scopes:",
                           "    @PerTest class ScopedType",
                           "    ScopedType is requested at",
-                          "        MyComponent.string()",
+                          "        [MyComponent] MyComponent.string()",
                           "",
                           "    @Provides @PerTest String ScopedModule.string()",
                           "",
diff --git a/javatests/dagger/internal/codegen/SetMultibindingValidationTest.java b/javatests/dagger/internal/codegen/SetMultibindingValidationTest.java
new file mode 100644
index 0000000..5933a43
--- /dev/null
+++ b/javatests/dagger/internal/codegen/SetMultibindingValidationTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2024 The Dagger 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
+ *
+ * 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 dagger.internal.codegen;
+
+import androidx.room.compiler.processing.util.Source;
+import com.google.common.collect.ImmutableList;
+import dagger.testing.compile.CompilerTests;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SetMultibindingValidationTest {
+  @Parameters(name = "{0}")
+  public static ImmutableList<Object[]> parameters() {
+    return CompilerMode.TEST_PARAMETERS;
+  }
+
+  private final CompilerMode compilerMode;
+
+  public SetMultibindingValidationTest(CompilerMode compilerMode) {
+    this.compilerMode = compilerMode;
+  }
+
+  @Test
+  public void setBindingOfProduced_provides() {
+    Source providesModule =
+        CompilerTests.javaSource(
+            "test.SetModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.IntoSet;",
+            "import dagger.producers.Produced;",
+            "",
+            "@Module",
+            "abstract class SetModule {",
+            "",
+            "  @Provides",
+            "  @IntoSet",
+            "  static Produced<String> provideProducer() {",
+            "    return null;",
+            "  }",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source providesComponent = component("");
+
+    CompilerTests.daggerCompiler(providesModule, providesComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Provides methods with @IntoSet/@ElementsIntoSet must not return framework "
+                  + "types");
+              subject.hasErrorContaining("test.SetModule has errors")
+                  .onSource(providesComponent)
+                  .onLineContaining("@Component(modules = {SetModule.class})");
+            });
+  }
+
+  @Test
+  public void setBindingOfProduced_binds() {
+
+    Source bindsModule =
+        CompilerTests.javaSource(
+            "test.SetModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Binds;",
+            "import dagger.multibindings.IntoSet;",
+            "import dagger.producers.Produced;",
+            "",
+            "@Module",
+            "abstract class SetModule {",
+            "",
+            "  @Binds",
+            "  @IntoSet",
+            "  abstract Produced<String> provideProvider(Produced<String> impl);",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source bindsComponent = component("");
+
+    CompilerTests.daggerCompiler(bindsModule, bindsComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Binds methods with @IntoSet/@ElementsIntoSet must not return framework types");
+              subject.hasErrorContaining("test.SetModule has errors")
+                  .onSource(bindsComponent)
+                  .onLineContaining("@Component(modules = {SetModule.class})");
+            });
+  }
+
+  @Test
+  public void elementsIntoSetBindingOfProduced_provides() {
+    Source providesModule =
+        CompilerTests.javaSource(
+            "test.SetModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Provides;",
+            "import dagger.multibindings.ElementsIntoSet;",
+            "import dagger.producers.Produced;",
+            "import java.util.Set;",
+            "",
+            "@Module",
+            "abstract class SetModule {",
+            "",
+            "  @Provides",
+            "  @ElementsIntoSet",
+            "  static Set<Produced<String>> provideProducer() {",
+            "    return null;",
+            "  }",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source providesComponent = component("");
+
+    CompilerTests.daggerCompiler(providesModule, providesComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Provides methods with @IntoSet/@ElementsIntoSet must not return framework "
+                  + "types");
+              subject.hasErrorContaining("test.SetModule has errors")
+                  .onSource(providesComponent)
+                  .onLineContaining("@Component(modules = {SetModule.class})");
+            });
+  }
+
+  @Test
+  public void elementsIntoSetBindingOfProduced_binds() {
+
+    Source bindsModule =
+        CompilerTests.javaSource(
+            "test.SetModule",
+            "package test;",
+            "",
+            "import dagger.Module;",
+            "import dagger.Binds;",
+            "import dagger.multibindings.ElementsIntoSet;",
+            "import dagger.producers.Produced;",
+            "import java.util.Set;",
+            "",
+            "@Module",
+            "abstract class SetModule {",
+            "",
+            "  @Binds",
+            "  @ElementsIntoSet",
+            "  abstract Set<Produced<String>> provideProvider(Set<Produced<String>> impl);",
+            "}");
+
+    // Entry points aren't needed because the check we care about here is a module validation
+    Source bindsComponent = component("");
+
+    CompilerTests.daggerCompiler(bindsModule, bindsComponent)
+        .withProcessingOptions(compilerMode.processorOptions())
+        .compile(
+            subject -> {
+              subject.hasErrorCount(2);
+              subject.hasErrorContaining(
+                  "@Binds methods with @IntoSet/@ElementsIntoSet must not return framework types");
+              subject.hasErrorContaining("test.SetModule has errors")
+                  .onSource(bindsComponent)
+                  .onLineContaining("@Component(modules = {SetModule.class})");
+            });
+  }
+
+  private static Source component(String... entryPoints) {
+    return CompilerTests.javaSource(
+        "test.TestComponent",
+        ImmutableList.<String>builder()
+            .add(
+                "package test;",
+                "",
+                "import dagger.Component;",
+                "import dagger.producers.Producer;",
+                "import java.util.Set;",
+                "import javax.inject.Provider;",
+                "",
+                "@Component(modules = {SetModule.class})",
+                "interface TestComponent {")
+            .add(entryPoints)
+            .add("}")
+            .build());
+  }
+}
diff --git a/javatests/dagger/internal/codegen/SourceFilesTest.java b/javatests/dagger/internal/codegen/SourceFilesTest.java
index c2f7dfd6..55e4ce5 100644
--- a/javatests/dagger/internal/codegen/SourceFilesTest.java
+++ b/javatests/dagger/internal/codegen/SourceFilesTest.java
@@ -17,9 +17,8 @@
 package dagger.internal.codegen;
 
 import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
 
-import com.squareup.javapoet.ClassName;
+import androidx.room.compiler.codegen.XClassName;
 import dagger.internal.codegen.binding.SourceFiles;
 import java.util.List;
 import org.junit.Test;
@@ -34,15 +33,15 @@
   @Test
   public void testSimpleVariableName_typeCollisions() {
     // a handful of boxed types
-    assertThat(simpleVariableName(ClassName.get(Long.class))).isEqualTo("l");
-    assertThat(simpleVariableName(ClassName.get(Double.class))).isEqualTo("d");
+    assertThat(simpleVariableName(Long.class)).isEqualTo("l");
+    assertThat(simpleVariableName(Double.class)).isEqualTo("d");
     // not a boxed type type, but a custom type might collide
-    assertThat(simpleVariableName(ClassName.get(Int.class))).isEqualTo("i");
+    assertThat(simpleVariableName(Int.class)).isEqualTo("i");
     // void is the weird pseudo-boxed type
-    assertThat(simpleVariableName(ClassName.get(Void.class))).isEqualTo("v");
+    assertThat(simpleVariableName(Void.class)).isEqualTo("v");
     // reflective types
-    assertThat(simpleVariableName(ClassName.get(Class.class))).isEqualTo("clazz");
-    assertThat(simpleVariableName(ClassName.get(Package.class))).isEqualTo("pkg");
+    assertThat(simpleVariableName(Class.class)).isEqualTo("clazz");
+    assertThat(simpleVariableName(Package.class)).isEqualTo("pkg");
   }
 
   private static final class For {}
@@ -51,13 +50,18 @@
 
   @Test
   public void testSimpleVariableName_randomKeywords() {
-    assertThat(simpleVariableName(ClassName.get(For.class))).isEqualTo("for_");
-    assertThat(simpleVariableName(ClassName.get(Goto.class))).isEqualTo("goto_");
+    assertThat(simpleVariableName(For.class)).isEqualTo("for_");
+    assertThat(simpleVariableName(Goto.class)).isEqualTo("goto_");
   }
 
   @Test
   public void testSimpleVariableName() {
-    assertThat(simpleVariableName(ClassName.get(Object.class))).isEqualTo("object");
-    assertThat(simpleVariableName(ClassName.get(List.class))).isEqualTo("list");
+    assertThat(simpleVariableName(Object.class)).isEqualTo("object");
+    assertThat(simpleVariableName(List.class)).isEqualTo("list");
+  }
+
+  private static String simpleVariableName(Class<?> clazz) {
+    return SourceFiles.simpleVariableName(
+        XClassName.Companion.get(clazz.getPackageName(), clazz.getSimpleName()));
   }
 }
diff --git a/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java
index 3a3da57..8c23102 100644
--- a/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java
+++ b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java
@@ -16,21 +16,15 @@
 
 package dagger.internal.codegen;
 
-import static androidx.room.compiler.processing.util.ProcessorTestExtKt.runProcessorTest;
 import static com.google.common.truth.Truth.assertThat;
 import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
 import static dagger.internal.codegen.xprocessing.XTypes.stripVariances;
 
 import androidx.room.compiler.processing.XMethodElement;
-import androidx.room.compiler.processing.XProcessingEnvConfig;
 import androidx.room.compiler.processing.XTypeElement;
 import androidx.room.compiler.processing.util.Source;
-import androidx.room.compiler.processing.util.XTestInvocation;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.squareup.javapoet.TypeName;
 import dagger.testing.compile.CompilerTests;
-import java.util.function.Function;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -149,53 +143,39 @@
 
   @Test
   public void typeVariableSameVariableName() {
-    runTest(
+    CompilerTests.invocationCompiler(
         CompilerTests.javaSource(
-            "Subject",
-            "interface Subject {",
-            "  <T extends Bar> Foo<T> method1();",
-            "  <T extends Baz> Foo<T> method2();",
-            "",
-            "  interface Foo<T> {}",
-            "  interface Bar {}",
-            "  interface Baz {}",
-            "}"),
-        invocation -> {
-          XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
-          TypeName method1ReturnTypeName =
-              getDeclaredMethod(subject, "method1").getReturnType().getTypeName();
-          TypeName method2ReturnTypeName =
-              getDeclaredMethod(subject, "method2").getReturnType().getTypeName();
-          assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName);
-          return null;
-        });
+              "Subject",
+              "interface Subject {",
+              "  <T extends Bar> Foo<T> method1();",
+              "  <T extends Baz> Foo<T> method2();",
+              "",
+              "  interface Foo<T> {}",
+              "  interface Bar {}",
+              "  interface Baz {}",
+              "}"))
+        .compile(
+            invocation -> {
+              XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
+              TypeName method1ReturnTypeName =
+                  getDeclaredMethod(subject, "method1").getReturnType().getTypeName();
+              TypeName method2ReturnTypeName =
+                  getDeclaredMethod(subject, "method2").getReturnType().getTypeName();
+              assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName);
+            });
   }
 
   private static void assertStrippedWildcardTypeNameEquals(Source source, String strippedTypeName) {
-    runTest(
-        source,
-        invocation -> {
-          XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
-          TypeName returnTypeName =
-              getDeclaredMethod(subject, "method").getReturnType().getTypeName();
-          assertThat(stripVariances(returnTypeName).toString().replace("Subject.", ""))
-              .isEqualTo(strippedTypeName);
-          return null;
-        });
-  }
-
-  private static void runTest(Source source, Function<XTestInvocation, Void> handler) {
-    runProcessorTest(
-        ImmutableList.of(source),
-        /* classpath = */ ImmutableList.of(),
-        /* options = */ ImmutableMap.of(),
-        /* javacArguments = */ ImmutableList.of(),
-        /* kotlincArguments = */ ImmutableList.of(),
-        /* config = */ new XProcessingEnvConfig.Builder().build(),
-        /* handler = */ invocation -> {
-          handler.apply(invocation);
-          return null;
-        });
+    CompilerTests.invocationCompiler(source)
+        .compile(
+            invocation -> {
+              XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
+              TypeName returnTypeName =
+                  getDeclaredMethod(subject, "method").getReturnType().getTypeName();
+              assertThat(stripVariances(returnTypeName).toString().replace("Subject.", ""))
+                  .isEqualTo(strippedTypeName);
+            }
+        );
   }
 
   private static XMethodElement getDeclaredMethod(XTypeElement typeElement, String jvmName) {
diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
index ce7197a..0a1873c 100644
--- a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
@@ -25,6 +25,7 @@
     srcs = glob(["*.java"]),
     functional = False,
     javacopts = DOCLINT_HTML_AND_SYNTAX,
+    shard_count = 3,
     deps = [
         "//java/dagger/internal/codegen/bindinggraphvalidation",
         "//java/dagger/internal/codegen/xprocessing",
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_DEFAULT_MODE_test.DaggerTestComponent
index ebea812..0f119c2 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_FAST_INIT_MODE_test.DaggerTestComponent
index f522a42..34b0dfe 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_assistedParamConflictsWithComponentFieldName_successfulyDeduped_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_DEFAULT_MODE_test.DaggerTestComponent
index bdd35a5..00ee294 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_FAST_INIT_MODE_test.DaggerTestComponent
index 2d5efe6..cf3e61c 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactoryCycle_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_DEFAULT_MODE_test.DaggerTestComponent
index ebea812..0f119c2 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_FAST_INIT_MODE_test.DaggerTestComponent
index db44f08..7ab24dd 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testAssistedFactory_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_DEFAULT_MODE_test.Foo_Factory b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_DEFAULT_MODE_test.Foo_Factory
index 0ae501c..23c6cff 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_DEFAULT_MODE_test.Foo_Factory
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_DEFAULT_MODE_test.Foo_Factory
@@ -1,10 +1,11 @@
 package test;
 
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Foo_Factory {
   private final Provider<Bar> argProvider;
@@ -31,6 +34,10 @@
     return newInstance(argProvider.get(), argProvider2);
   }
 
+  public static Foo_Factory create(javax.inject.Provider<Bar> argProvider) {
+    return new Foo_Factory(Providers.asDaggerProvider(argProvider));
+  }
+
   public static Foo_Factory create(Provider<Bar> argProvider) {
     return new Foo_Factory(argProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_FAST_INIT_MODE_test.Foo_Factory b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_FAST_INIT_MODE_test.Foo_Factory
index 0ae501c..23c6cff 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_FAST_INIT_MODE_test.Foo_Factory
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testFactoryGeneratorDuplicatedParamNames_FAST_INIT_MODE_test.Foo_Factory
@@ -1,10 +1,11 @@
 package test;
 
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Foo_Factory {
   private final Provider<Bar> argProvider;
@@ -31,6 +34,10 @@
     return newInstance(argProvider.get(), argProvider2);
   }
 
+  public static Foo_Factory create(javax.inject.Provider<Bar> argProvider) {
+    return new Foo_Factory(Providers.asDaggerProvider(argProvider));
+  }
+
   public static Foo_Factory create(Provider<Bar> argProvider) {
     return new Foo_Factory(argProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_DEFAULT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_DEFAULT_MODE_test.DaggerMyComponent
index b3fc316..b2e2831 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_DEFAULT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_DEFAULT_MODE_test.DaggerMyComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_FAST_INIT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_FAST_INIT_MODE_test.DaggerMyComponent
index 68c5a77..2a23645 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_FAST_INIT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testMultipleAssistedFactoryInDifferentComponents_FAST_INIT_MODE_test.DaggerMyComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_DEFAULT_MODE_test.DaggerTestComponent
index f94d608..daaf665 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_FAST_INIT_MODE_test.DaggerTestComponent
index 0726e0f..41faaab 100644
--- a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest_testParameterizedAssistParam_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_DEFAULT_MODE_test.DaggerTestComponent
index 7aed6ce..e2576ae 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_FAST_INIT_MODE_test.DaggerTestComponent
index 7aed6ce..e2576ae 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentBuilderTest_testUsesBuildAndSetterNames_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
index 384875a..a4a94cb 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
index b4fa619..6df65af 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
index 384875a..a4a94cb 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
index b4fa619..6df65af 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCanInstantiateModulesUserCannotSet_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 510db53..ee2e44d 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index c31b4ab..17364a3 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 510db53..ee2e44d 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index c31b4ab..17364a3 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithBindsInstanceNoStaticCreateGenerated_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 77058c3..133f141 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index 6583a23..ebc41b7 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 77058c3..133f141 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index 6583a23..ebc41b7 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testCreatorWithPrimitiveBindsInstance_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 5040a78..325c101 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index 10bc365..4910ba9 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=DEFAULT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
index 5040a78..325c101 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Builder_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
index 10bc365..4910ba9 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentCreatorTest_testEmptyCreator_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Component.Factory_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_DEFAULT_MODE_test.DaggerTestComponent
index ac6ba38..a0178c5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_FAST_INIT_MODE_test.DaggerTestComponent
index ac6ba38..a0178c5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentFactoryTest_testUsesParameterNames_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_DEFAULT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_DEFAULT_MODE_test.DaggerBComponent
index dc3a6e7..59ce365 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_DEFAULT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_DEFAULT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_FAST_INIT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
index 87aba7d..10beda6 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_arrayComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_DEFAULT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_DEFAULT_MODE_test.DaggerBComponent
index 0626b32..19f49ac 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_DEFAULT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_DEFAULT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_FAST_INIT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_FAST_INIT_MODE_test.DaggerBComponent
index 26b5f28..990d8ca 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_FAST_INIT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentDependency_FAST_INIT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_DEFAULT_MODE_test.DaggerSimpleComponent
index 66af8f5..95c8773 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
index 4ce6af3..23bf006 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_DEFAULT_MODE_test.DaggerParent
index 2f1124b..df9d533 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_DEFAULT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_FAST_INIT_MODE_test.DaggerParent
index 7d9a5d3..e38e8f3 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentMethodInChildCallsComponentMethodInParent_FAST_INIT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_DEFAULT_MODE_test.DaggerTestComponent
index 03fcd70..70d58b2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_FAST_INIT_MODE_test.DaggerTestComponent
index 03fcd70..70d58b2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithAbstractModule_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_DEFAULT_MODE_test.DaggerTestComponent
index 8d8ddad..70c1303 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_FAST_INIT_MODE_test.DaggerTestComponent
index 8d8ddad..70c1303 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithModule_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_DEFAULT_MODE_test.DaggerSimpleComponent
index b79b07d..97f27e4 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_FAST_INIT_MODE_test.DaggerSimpleComponent
index e89783c..f3255ca 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_componentWithScope_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_DEFAULT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_DEFAULT_MODE_test.DaggerBComponent
index a2d1d85..a983d5a 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_DEFAULT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_DEFAULT_MODE_test.DaggerBComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_FAST_INIT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_FAST_INIT_MODE_test.DaggerBComponent
index 42a0386..a595a98 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_FAST_INIT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_dependencyNameCollision_FAST_INIT_MODE_test.DaggerBComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_DEFAULT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_DEFAULT_MODE_test.DaggerBComponent
index b284dbd..009e4e8 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_DEFAULT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_DEFAULT_MODE_test.DaggerBComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_FAST_INIT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_FAST_INIT_MODE_test.DaggerBComponent
index b284dbd..009e4e8 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_FAST_INIT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_ignoresDependencyMethodsFromObject_FAST_INIT_MODE_test.DaggerBComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
index 898e877..af5d9b1 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
index 898e877..af5d9b1 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_justInTimeAtInjectConstructor_hasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_DEFAULT_MODE_test.DaggerSimpleComponent
index d991e42..c0b1ee8 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
index d991e42..c0b1ee8 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjection_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
index dd93201..4ce5ae9 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
index dd93201..4ce5ae9 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleHasGeneratedQualifier_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_DEFAULT_MODE_test.DaggerTestComponent
index 872646f..8e94a54 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_FAST_INIT_MODE_test.DaggerTestComponent
index 872646f..8e94a54 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_moduleNameCollision_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.DaggerTestComponent
index b9a27eb..7cadd4d 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.TestModule_PrimitiveIntegerFactory b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.TestModule_PrimitiveIntegerFactory
index 4caa6e1..501fd25 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.TestModule_PrimitiveIntegerFactory
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_DEFAULT_MODE_test.TestModule_PrimitiveIntegerFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_PrimitiveIntegerFactory implements Factory<Integer> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_PrimitiveIntegerFactory INSTANCE = new TestModule_PrimitiveIntegerFactory();
+    static final TestModule_PrimitiveIntegerFactory INSTANCE = new TestModule_PrimitiveIntegerFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.DaggerTestComponent
index b9a27eb..7cadd4d 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.TestModule_PrimitiveIntegerFactory b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.TestModule_PrimitiveIntegerFactory
index 4caa6e1..501fd25 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.TestModule_PrimitiveIntegerFactory
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullCheckingIgnoredWhenProviderReturnsPrimitive_FAST_INIT_MODE_test.TestModule_PrimitiveIntegerFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_PrimitiveIntegerFactory implements Factory<Integer> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_PrimitiveIntegerFactory INSTANCE = new TestModule_PrimitiveIntegerFactory();
+    static final TestModule_PrimitiveIntegerFactory INSTANCE = new TestModule_PrimitiveIntegerFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.DaggerTestComponent
index 54425a7..553c4a2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.TestModule_NonNullableStringFactory b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.TestModule_NonNullableStringFactory
index 96e8708..2b294e0 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.TestModule_NonNullableStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_DEFAULT_MODE_test.TestModule_NonNullableStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_NonNullableStringFactory implements Factory<String> {
   @Override
@@ -36,7 +38,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_NonNullableStringFactory INSTANCE = new TestModule_NonNullableStringFactory();
+    static final TestModule_NonNullableStringFactory INSTANCE = new TestModule_NonNullableStringFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.DaggerTestComponent
index 54425a7..553c4a2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.TestModule_NonNullableStringFactory b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.TestModule_NonNullableStringFactory
index 96e8708..2b294e0 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.TestModule_NonNullableStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_nullIncorrectlyReturnedFromNonNullableInlinedProvider_FAST_INIT_MODE_test.TestModule_NonNullableStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_NonNullableStringFactory implements Factory<String> {
   @Override
@@ -36,7 +38,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_NonNullableStringFactory INSTANCE = new TestModule_NonNullableStringFactory();
+    static final TestModule_NonNullableStringFactory INSTANCE = new TestModule_NonNullableStringFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_DEFAULT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_DEFAULT_MODE_test.DaggerBComponent
index c1a2108..aedfabd 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_DEFAULT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_DEFAULT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_FAST_INIT_MODE_test.DaggerBComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
index d88c74e..2f5673b 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_primitiveComponentDependency_FAST_INIT_MODE_test.DaggerBComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerBComponent {
   private DaggerBComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_DEFAULT_MODE_test.DaggerParent
index 73f067b..489e557 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_DEFAULT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_FAST_INIT_MODE_test.DaggerParent
index c20b8f0..22f50bc 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_privateMethodUsedOnlyInChildDoesNotUseQualifiedThis_FAST_INIT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_DEFAULT_MODE_test.DaggerTestComponent
index 5558c81..7654c52 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_FAST_INIT_MODE_test.DaggerTestComponent
index e19505d..c9ae9dd 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_providerComponentType_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_DEFAULT_MODE_test.DaggerPublicComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_DEFAULT_MODE_test.DaggerPublicComponent
index 48c0f34..9237934 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_DEFAULT_MODE_test.DaggerPublicComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_DEFAULT_MODE_test.DaggerPublicComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerPublicComponent {
   private DaggerPublicComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_FAST_INIT_MODE_test.DaggerPublicComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_FAST_INIT_MODE_test.DaggerPublicComponent
index 48c0f34..9237934 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_FAST_INIT_MODE_test.DaggerPublicComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_publicComponentType_FAST_INIT_MODE_test.DaggerPublicComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerPublicComponent {
   private DaggerPublicComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_DEFAULT_MODE_test.DaggerTestComponent
index 22771bb..cdb0fa7 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_FAST_INIT_MODE_test.DaggerTestComponent
index 22771bb..cdb0fa7 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_resolutionOrder_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_DEFAULT_MODE_test.DaggerOuterType_SimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_DEFAULT_MODE_test.DaggerOuterType_SimpleComponent
index 1a79810..c107cec 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_DEFAULT_MODE_test.DaggerOuterType_SimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_DEFAULT_MODE_test.DaggerOuterType_SimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerOuterType_SimpleComponent {
   private DaggerOuterType_SimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_FAST_INIT_MODE_test.DaggerOuterType_SimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_FAST_INIT_MODE_test.DaggerOuterType_SimpleComponent
index 1a79810..c107cec 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_FAST_INIT_MODE_test.DaggerOuterType_SimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponentWithNesting_FAST_INIT_MODE_test.DaggerOuterType_SimpleComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerOuterType_SimpleComponent {
   private DaggerOuterType_SimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
index e1e3f64..7dee796 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
index 094c1ff..c85bae0 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_DEFAULT_MODE_test.DaggerSimpleComponent
index 108b13d..04c2ad5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_FAST_INIT_MODE_test.DaggerSimpleComponent
index 108b13d..04c2ad5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_inheritedComponentMethodDep_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_DEFAULT_MODE_test.DaggerSimpleComponent
index 108b13d..04c2ad5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_FAST_INIT_MODE_test.DaggerSimpleComponent
index 108b13d..04c2ad5 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_simpleComponent_redundantComponentMethod_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_DEFAULT_MODE_test.DaggerParent
index c630533..2fd99c4 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_DEFAULT_MODE_test.DaggerParent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_FAST_INIT_MODE_test.DaggerParent
index c630533..2fd99c4 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_subcomponentNotGeneratedIfNotUsedInGraph_FAST_INIT_MODE_test.DaggerParent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_DEFAULT_MODE_test.DaggerTestComponent
index 7b077e7..e21c509 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_FAST_INIT_MODE_test.DaggerTestComponent
index 7b077e7..e21c509 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_transitiveModuleDeps_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_DEFAULT_MODE_test.DaggerParent
index 9fcf3dc..7bc733e 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_DEFAULT_MODE_test.DaggerParent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_FAST_INIT_MODE_test.DaggerParent
index 9fcf3dc..7bc733e 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_unusedSubcomponents_dontResolveExtraBindingsInParentComponents_FAST_INIT_MODE_test.DaggerParent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_DEFAULT_MODE_test.DaggerTestComponent
index a036546..7f85c85 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_FAST_INIT_MODE_test.DaggerTestComponent
index 7defcfc..d7c83f6 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentProtectedTypeTest_componentAccessesProtectedType_succeeds_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_DEFAULT_MODE_test.DaggerTestComponent
index bbe89b9..1a677ba 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_FAST_INIT_MODE_test.DaggerTestComponent
index bbe89b9..1a677ba 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_bindsInstance_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_DEFAULT_MODE_test.DaggerTestComponent
index 98ba4b6..fe34d7b 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_FAST_INIT_MODE_test.DaggerTestComponent
index 98ba4b6..fe34d7b 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentInstances_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_DEFAULT_MODE_test.DaggerTestComponent
index 9b39816..353bc44 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_FAST_INIT_MODE_test.DaggerTestComponent
index 94ebb33..7e27883 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_componentRequirementNeededInFactoryCreationOfSubcomponent_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_DEFAULT_MODE_test.DaggerTestComponent
index 99caa07..ef794e6 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_FAST_INIT_MODE_test.DaggerTestComponent
index 99caa07..ef794e6 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_instanceModuleMethod_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent
new file mode 100644
index 0000000..e484861
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent
@@ -0,0 +1,43 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+final class DaggerTestComponent {
+  private DaggerTestComponent() {
+  }
+
+  public static TestComponent.Factory factory() {
+    return new Factory();
+  }
+
+  private static final class Factory implements TestComponent.Factory {
+    @Override
+    public TestComponent create(@Nullable Bar arg) {
+      return new TestComponentImpl(arg);
+    }
+  }
+
+  private static final class TestComponentImpl implements TestComponent {
+    private final TestComponentImpl testComponentImpl = this;
+
+    private TestComponentImpl(@Nullable Bar argParam) {
+
+
+    }
+  }
+}
\ No newline at end of file
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent
new file mode 100644
index 0000000..95c1668
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent
@@ -0,0 +1,43 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+final class DaggerTestComponent {
+  private DaggerTestComponent() {
+  }
+
+  public static TestComponent.Factory factory() {
+    return new Factory();
+  }
+
+  private static final class Factory implements TestComponent.Factory {
+    @Override
+    public TestComponent create(@Nullable Bar arg) {
+      return new TestComponentImpl(arg);
+    }
+  }
+
+  private static final class TestComponentImpl implements TestComponent {
+    private final TestComponentImpl testComponentImpl = this;
+
+    private TestComponentImpl(@Nullable Bar argParam) {
+
+
+    }
+  }
+}
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent
new file mode 100644
index 0000000..95c1668
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent
@@ -0,0 +1,43 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+final class DaggerTestComponent {
+  private DaggerTestComponent() {
+  }
+
+  public static TestComponent.Factory factory() {
+    return new Factory();
+  }
+
+  private static final class Factory implements TestComponent.Factory {
+    @Override
+    public TestComponent create(@Nullable Bar arg) {
+      return new TestComponentImpl(arg);
+    }
+  }
+
+  private static final class TestComponentImpl implements TestComponent {
+    private final TestComponentImpl testComponentImpl = this;
+
+    private TestComponentImpl(@Nullable Bar argParam) {
+
+
+    }
+  }
+}
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent
new file mode 100644
index 0000000..95c1668
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent
@@ -0,0 +1,43 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+final class DaggerTestComponent {
+  private DaggerTestComponent() {
+  }
+
+  public static TestComponent.Factory factory() {
+    return new Factory();
+  }
+
+  private static final class Factory implements TestComponent.Factory {
+    @Override
+    public TestComponent create(@Nullable Bar arg) {
+      return new TestComponentImpl(arg);
+    }
+  }
+
+  private static final class TestComponentImpl implements TestComponent {
+    private final TestComponentImpl testComponentImpl = this;
+
+    private TestComponentImpl(@Nullable Bar argParam) {
+
+
+    }
+  }
+}
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
index a2c9032..c89184d 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
index 5d58c6e..8c5c484 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreatedWithDependencies_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
index 59a7cae..68ee495 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
index 9a84c85..7eabde2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
index 13f15e0..e71c32a 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_DEFAULT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
index f2a4aa6..effc678 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardSubcomponentCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testCmdLineOptionEnabledPrecedesAnnotationDisabled_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testCmdLineOptionEnabledPrecedesAnnotationDisabled_test.DaggerSimpleComponent
index 094c1ff..c85bae0 100644
--- a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testCmdLineOptionEnabledPrecedesAnnotationDisabled_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testCmdLineOptionEnabledPrecedesAnnotationDisabled_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitEnabledFromAnnotationSucceeded_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitEnabledFromAnnotationSucceeded_test.DaggerSimpleComponent
index 094c1ff..c85bae0 100644
--- a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitEnabledFromAnnotationSucceeded_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitEnabledFromAnnotationSucceeded_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitaDisabledFromAnnotationSucceeded_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitaDisabledFromAnnotationSucceeded_test.DaggerSimpleComponent
index e1e3f64..7dee796 100644
--- a/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitaDisabledFromAnnotationSucceeded_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/DaggerProcessingOptionsTest_testFastInitaDisabledFromAnnotationSucceeded_test.DaggerSimpleComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_DEFAULT_MODE_test.DaggerTestComponent
index 0cf470e..8b138de 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_FAST_INIT_MODE_test.DaggerTestComponent
index f7bd448..8a86532 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castNeeded_rawTypes_Provider_get_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_DEFAULT_MODE_test.DaggerTestComponent
index d5ebea6..cab6003 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_FAST_INIT_MODE_test.DaggerTestComponent
index dda8836..800a764 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_castedToRawType_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_DEFAULT_MODE_test.DaggerTestComponent
index 8a2c7de..8eaaaed 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_FAST_INIT_MODE_test.DaggerTestComponent
index 5c9ce8a..8abc7f8 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_doubleBinds_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_DEFAULT_MODE_test.DaggerRequestsSubtypeAsProvider b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_DEFAULT_MODE_test.DaggerRequestsSubtypeAsProvider
index a8ad72f..92b7b32 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_DEFAULT_MODE_test.DaggerRequestsSubtypeAsProvider
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_DEFAULT_MODE_test.DaggerRequestsSubtypeAsProvider
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerRequestsSubtypeAsProvider {
   private DaggerRequestsSubtypeAsProvider() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_FAST_INIT_MODE_test.DaggerRequestsSubtypeAsProvider b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_FAST_INIT_MODE_test.DaggerRequestsSubtypeAsProvider
index 6f6e32c..474db4f 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_FAST_INIT_MODE_test.DaggerRequestsSubtypeAsProvider
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_inlineFactoryOfInacessibleType_FAST_INIT_MODE_test.DaggerRequestsSubtypeAsProvider
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerRequestsSubtypeAsProvider {
   private DaggerRequestsSubtypeAsProvider() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
index 9e96fba..683231a 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
index 059eaab..258ed43 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_noCast_rawTypes_Provider_get_toInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_DEFAULT_MODE_test.DaggerTestComponent
index a8a4aad..6ab9548 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_FAST_INIT_MODE_test.DaggerTestComponent
index 40dcf73..2ba405b 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_providerWhenBindsScopeGreaterThanDependencyScope_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_DEFAULT_MODE_test.DaggerTestComponent
index 4877c33..fe9cfaf 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_FAST_INIT_MODE_test.DaggerTestComponent
index 08c5844..c67cc9e 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toDoubleCheck_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_DEFAULT_MODE_test.DaggerTestComponent
index e04aae6..28b0f8f 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_FAST_INIT_MODE_test.DaggerTestComponent
index 2ca627d..30d42c8 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toSingleCheck_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_DEFAULT_MODE_test.DaggerTestComponent
index e3d5bf6..8cfcdee 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_FAST_INIT_MODE_test.DaggerTestComponent
index 93973b6..8d0d51e 100644
--- a/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/DelegateRequestRepresentationTest_toUnscoped_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_DEFAULT_MODE_test.DaggerSimpleComponent
index 416d9c2..5f66fd2 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_FAST_INIT_MODE_test.DaggerSimpleComponent
index 64762bd..3ec2b3b 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_scopedBinding_onlyUsedInSubcomponent_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
index 39dc9c5..a8b4832 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
index 39dc9c5..a8b4832 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_DEFAULT_MODE_test.DaggerSimpleComponent
index d11d1ab..730f7ef 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_DEFAULT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_DEFAULT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_FAST_INIT_MODE_test.DaggerSimpleComponent
index acf83f2..40aeab2 100644
--- a/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ElidedFactoriesTest_simpleComponent_injectsProviderOf_dependsOnScoped_FAST_INIT_MODE_test.DaggerSimpleComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerSimpleComponent {
   private DaggerSimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index e752840..0000000
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,75 +0,0 @@
-package test;
-
-import dagger.internal.DaggerGenerated;
-import dagger.internal.DelegateFactory;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
-import other.OtherEntryPoint;
-import other.OtherEntryPoint_Factory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private Provider<Foo> bindProvider;
-
-    @SuppressWarnings("rawtypes")
-    private Provider fooImplProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    private Object fooImpl() {
-      return FooImpl_Factory.newInstance(bindProvider);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.bindProvider = new DelegateFactory<>();
-      this.fooImplProvider = FooImpl_Factory.create(bindProvider);
-      DelegateFactory.setDelegate(bindProvider, DoubleCheck.provider((Provider) fooImplProvider));
-    }
-
-    @Override
-    public OtherEntryPoint getOtherEntryPoint() {
-      return OtherEntryPoint_Factory.newInstance(fooImpl());
-    }
-  }
-}
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
index 7990079..ab10526 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index bf80e63..0000000
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,97 +0,0 @@
-package test;
-
-import dagger.internal.DaggerGenerated;
-import dagger.internal.DelegateFactory;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
-import other.OtherEntryPoint;
-import other.OtherEntryPoint_Factory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private Provider<Foo> bindProvider;
-
-    @SuppressWarnings("rawtypes")
-    private Provider fooImplProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    private Object fooImpl() {
-      return FooImpl_Factory.newInstance(bindProvider);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.bindProvider = new DelegateFactory<>();
-      this.fooImplProvider = new SwitchingProvider<Object>(testComponentImpl, 0);
-      DelegateFactory.setDelegate(bindProvider, DoubleCheck.provider((Provider) fooImplProvider));
-    }
-
-    @Override
-    public OtherEntryPoint getOtherEntryPoint() {
-      return OtherEntryPoint_Factory.newInstance(fooImpl());
-    }
-
-    private static final class SwitchingProvider<T> implements Provider<T> {
-      private final TestComponentImpl testComponentImpl;
-
-      private final int id;
-
-      SwitchingProvider(TestComponentImpl testComponentImpl, int id) {
-        this.testComponentImpl = testComponentImpl;
-        this.id = id;
-      }
-
-      @SuppressWarnings("unchecked")
-      @Override
-      public T get() {
-        switch (id) {
-          case 0: // other.FooImpl 
-          return (T) FooImpl_Factory.newInstance(testComponentImpl.bindProvider);
-
-          default: throw new AssertionError(id);
-        }
-      }
-    }
-  }
-}
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
index f92f558..90c0f4f 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index f13d94a..0000000
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,71 +0,0 @@
-package test;
-
-import dagger.internal.DaggerGenerated;
-import dagger.internal.DelegateFactory;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
-import other.OtherEntryPoint;
-import other.OtherEntryPoint_Factory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    @SuppressWarnings("rawtypes")
-    private Provider fooImplProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    private Object fooImpl() {
-      return FooImpl_Factory.newInstance(fooImplProvider);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.fooImplProvider = new DelegateFactory<>();
-      DelegateFactory.setDelegate(fooImplProvider, FooImpl_Factory.create(fooImplProvider));
-    }
-
-    @Override
-    public OtherEntryPoint getOtherEntryPoint() {
-      return OtherEntryPoint_Factory.newInstance(fooImpl());
-    }
-  }
-}
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
index 30be4f1..048e7ee 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index 27a30fb..0000000
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,93 +0,0 @@
-package test;
-
-import dagger.internal.DaggerGenerated;
-import dagger.internal.DelegateFactory;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
-import other.OtherEntryPoint;
-import other.OtherEntryPoint_Factory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    @SuppressWarnings("rawtypes")
-    private Provider fooImplProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    private Object fooImpl() {
-      return FooImpl_Factory.newInstance(fooImplProvider);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.fooImplProvider = new DelegateFactory<>();
-      DelegateFactory.setDelegate(fooImplProvider, new SwitchingProvider<Object>(testComponentImpl, 0));
-    }
-
-    @Override
-    public OtherEntryPoint getOtherEntryPoint() {
-      return OtherEntryPoint_Factory.newInstance(fooImpl());
-    }
-
-    private static final class SwitchingProvider<T> implements Provider<T> {
-      private final TestComponentImpl testComponentImpl;
-
-      private final int id;
-
-      SwitchingProvider(TestComponentImpl testComponentImpl, int id) {
-        this.testComponentImpl = testComponentImpl;
-        this.id = id;
-      }
-
-      @SuppressWarnings("unchecked")
-      @Override
-      public T get() {
-        switch (id) {
-          case 0: // other.FooImpl 
-          return (T) FooImpl_Factory.newInstance(testComponentImpl.fooImplProvider);
-
-          default: throw new AssertionError(id);
-        }
-      }
-    }
-  }
-}
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
index 7146c06..d004f1b 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
index ca51d3f..b45151a 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index ce6bcdf..0000000
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,89 +0,0 @@
-package test;
-
-import dagger.internal.DaggerGenerated;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    @SuppressWarnings("rawtypes")
-    private Provider fooImplProvider;
-
-    private Provider<Foo> bindProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.fooImplProvider = new SwitchingProvider<Object>(testComponentImpl, 0);
-      this.bindProvider = DoubleCheck.provider((Provider) fooImplProvider);
-    }
-
-    @Override
-    public Foo getFoo() {
-      return bindProvider.get();
-    }
-
-    private static final class SwitchingProvider<T> implements Provider<T> {
-      private final TestComponentImpl testComponentImpl;
-
-      private final int id;
-
-      SwitchingProvider(TestComponentImpl testComponentImpl, int id) {
-        this.testComponentImpl = testComponentImpl;
-        this.id = id;
-      }
-
-      @SuppressWarnings("unchecked")
-      @Override
-      public T get() {
-        switch (id) {
-          case 0: // other.FooImpl 
-          return (T) FooImpl_Factory.newInstance();
-
-          default: throw new AssertionError(id);
-        }
-      }
-    }
-  }
-}
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
index c39381b..8709d08 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_basicNameCollision_test.InjectConstructor_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_basicNameCollision_test.InjectConstructor_Factory
index 8488aba..fc46a0b 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_basicNameCollision_test.InjectConstructor_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_basicNameCollision_test.InjectConstructor_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectConstructor_Factory implements Factory<InjectConstructor> {
   private final Provider<other.pkg.Factory> factoryProvider;
@@ -33,6 +36,11 @@
     return newInstance(factoryProvider.get());
   }
 
+  public static InjectConstructor_Factory create(
+      javax.inject.Provider<other.pkg.Factory> factoryProvider) {
+    return new InjectConstructor_Factory(Providers.asDaggerProvider(factoryProvider));
+  }
+
   public static InjectConstructor_Factory create(Provider<other.pkg.Factory> factoryProvider) {
     return new InjectConstructor_Factory(factoryProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_boundedGenerics_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_boundedGenerics_test.GenericClass_Factory
index 143d1ed..85f3cee 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_boundedGenerics_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_boundedGenerics_test.GenericClass_Factory
@@ -2,11 +2,12 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<A extends Number & Comparable<A>, B extends List<? extends String>, C extends List<? super String>> implements Factory<GenericClass<A, B, C>> {
   private final Provider<A> aProvider;
@@ -41,6 +44,12 @@
   }
 
   public static <A extends Number & Comparable<A>, B extends List<? extends String>, C extends List<? super String>> GenericClass_Factory<A, B, C> create(
+      javax.inject.Provider<A> aProvider, javax.inject.Provider<B> bProvider,
+      javax.inject.Provider<C> cProvider) {
+    return new GenericClass_Factory<A, B, C>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider), Providers.asDaggerProvider(cProvider));
+  }
+
+  public static <A extends Number & Comparable<A>, B extends List<? extends String>, C extends List<? super String>> GenericClass_Factory<A, B, C> create(
       Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider) {
     return new GenericClass_Factory<A, B, C>(aProvider, bProvider, cProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_fieldAndMethodGenerics_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_fieldAndMethodGenerics_test.GenericClass_Factory
index ab6d9ae..6e1e620 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_fieldAndMethodGenerics_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_fieldAndMethodGenerics_test.GenericClass_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {
   private final Provider<A> aProvider;
@@ -39,6 +42,11 @@
     return instance;
   }
 
+  public static <A, B> GenericClass_Factory<A, B> create(javax.inject.Provider<A> aProvider,
+      javax.inject.Provider<B> bProvider) {
+    return new GenericClass_Factory<A, B>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   public static <A, B> GenericClass_Factory<A, B> create(Provider<A> aProvider,
       Provider<B> bProvider) {
     return new GenericClass_Factory<A, B>(aProvider, bProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_genericClassWithNoDependencies_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_genericClassWithNoDependencies_test.GenericClass_Factory
index 95e0038..8f16b9a 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_genericClassWithNoDependencies_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_genericClassWithNoDependencies_test.GenericClass_Factory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {
   @Override
@@ -37,7 +39,7 @@
 
   private static final class InstanceHolder {
     @SuppressWarnings("rawtypes")
-    private static final GenericClass_Factory INSTANCE = new GenericClass_Factory();
+    static final GenericClass_Factory INSTANCE = new GenericClass_Factory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorAndMembersInjection_test.AllInjections_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorAndMembersInjection_test.AllInjections_Factory
index 0c2475c..1558b85 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorAndMembersInjection_test.AllInjections_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorAndMembersInjection_test.AllInjections_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class AllInjections_Factory implements Factory<AllInjections> {
   private final Provider<String> sProvider;
@@ -43,6 +46,11 @@
     return instance;
   }
 
+  public static AllInjections_Factory create(javax.inject.Provider<String> sProvider,
+      javax.inject.Provider<String> sProvider2, javax.inject.Provider<String> sProvider3) {
+    return new AllInjections_Factory(Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(sProvider2), Providers.asDaggerProvider(sProvider3));
+  }
+
   public static AllInjections_Factory create(Provider<String> sProvider,
       Provider<String> sProvider2, Provider<String> sProvider3) {
     return new AllInjections_Factory(sProvider, sProvider2, sProvider3);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorOnGenericClass_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorOnGenericClass_test.GenericClass_Factory
index 6ac47e9..bc48f59 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorOnGenericClass_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructorOnGenericClass_test.GenericClass_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {
   private final Provider<T> tProvider;
@@ -33,6 +36,10 @@
     return newInstance(tProvider.get());
   }
 
+  public static <T> GenericClass_Factory<T> create(javax.inject.Provider<T> tProvider) {
+    return new GenericClass_Factory<T>(Providers.asDaggerProvider(tProvider));
+  }
+
   public static <T> GenericClass_Factory<T> create(Provider<T> tProvider) {
     return new GenericClass_Factory<T>(tProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructor_test.InjectConstructor_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructor_test.InjectConstructor_Factory
index 638815e..8368ed3 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructor_test.InjectConstructor_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_injectConstructor_test.InjectConstructor_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectConstructor_Factory implements Factory<InjectConstructor> {
   private final Provider<String> sProvider;
@@ -33,6 +36,10 @@
     return newInstance(sProvider.get());
   }
 
+  public static InjectConstructor_Factory create(javax.inject.Provider<String> sProvider) {
+    return new InjectConstructor_Factory(Providers.asDaggerProvider(sProvider));
+  }
+
   public static InjectConstructor_Factory create(Provider<String> sProvider) {
     return new InjectConstructor_Factory(sProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_multipleSameTypesWithGenericsAndQualifiersAndLazies_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_multipleSameTypesWithGenericsAndQualifiersAndLazies_test.GenericClass_Factory
index a5b93b8..687848e 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_multipleSameTypesWithGenericsAndQualifiersAndLazies_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_multipleSameTypesWithGenericsAndQualifiersAndLazies_test.GenericClass_Factory
@@ -4,10 +4,11 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.DoubleCheck;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata("test.QualifierA")
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {
   private final Provider<A> aProvider;
@@ -81,6 +84,17 @@
     return newInstance(aProvider.get(), a2Provider.get(), paProvider, qaProvider.get(), DoubleCheck.lazy(laProvider), sProvider.get(), s2Provider.get(), psProvider, qsProvider.get(), DoubleCheck.lazy(lsProvider), bProvider.get(), b2Provider.get(), pbProvider, qbProvider.get(), DoubleCheck.lazy(lbProvider));
   }
 
+  public static <A, B> GenericClass_Factory<A, B> create(javax.inject.Provider<A> aProvider,
+      javax.inject.Provider<A> a2Provider, javax.inject.Provider<A> paProvider,
+      javax.inject.Provider<A> qaProvider, javax.inject.Provider<A> laProvider,
+      javax.inject.Provider<String> sProvider, javax.inject.Provider<String> s2Provider,
+      javax.inject.Provider<String> psProvider, javax.inject.Provider<String> qsProvider,
+      javax.inject.Provider<String> lsProvider, javax.inject.Provider<B> bProvider,
+      javax.inject.Provider<B> b2Provider, javax.inject.Provider<B> pbProvider,
+      javax.inject.Provider<B> qbProvider, javax.inject.Provider<B> lbProvider) {
+    return new GenericClass_Factory<A, B>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(a2Provider), Providers.asDaggerProvider(paProvider), Providers.asDaggerProvider(qaProvider), Providers.asDaggerProvider(laProvider), Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(s2Provider), Providers.asDaggerProvider(psProvider), Providers.asDaggerProvider(qsProvider), Providers.asDaggerProvider(lsProvider), Providers.asDaggerProvider(bProvider), Providers.asDaggerProvider(b2Provider), Providers.asDaggerProvider(pbProvider), Providers.asDaggerProvider(qbProvider), Providers.asDaggerProvider(lbProvider));
+  }
+
   public static <A, B> GenericClass_Factory<A, B> create(Provider<A> aProvider,
       Provider<A> a2Provider, Provider<A> paProvider, Provider<A> qaProvider,
       Provider<A> laProvider, Provider<String> sProvider, Provider<String> s2Provider,
@@ -90,9 +104,9 @@
     return new GenericClass_Factory<A, B>(aProvider, a2Provider, paProvider, qaProvider, laProvider, sProvider, s2Provider, psProvider, qsProvider, lsProvider, bProvider, b2Provider, pbProvider, qbProvider, lbProvider);
   }
 
-  public static <A, B> GenericClass<A, B> newInstance(A a, A a2, Provider<A> pa, A qa, Lazy<A> la,
-      String s, String s2, Provider<String> ps, String qs, Lazy<String> ls, B b, B b2,
-      Provider<B> pb, B qb, Lazy<B> lb) {
+  public static <A, B> GenericClass<A, B> newInstance(A a, A a2, javax.inject.Provider<A> pa, A qa,
+      Lazy<A> la, String s, String s2, javax.inject.Provider<String> ps, String qs, Lazy<String> ls,
+      B b, B b2, javax.inject.Provider<B> pb, B qb, Lazy<B> lb) {
     return new GenericClass<A, B>(a, a2, pa, qa, la, s, s2, ps, qs, ls, b, b2, pb, qb, lb);
   }
 }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_nestedNameCollision_test.InjectConstructor_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_nestedNameCollision_test.InjectConstructor_Factory
index f3337a1..0615073 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_nestedNameCollision_test.InjectConstructor_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_nestedNameCollision_test.InjectConstructor_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 import other.pkg.Outer;
 
 @ScopeMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectConstructor_Factory implements Factory<InjectConstructor> {
   private final Provider<Outer.Factory> factoryProvider;
@@ -34,6 +37,11 @@
     return newInstance(factoryProvider.get());
   }
 
+  public static InjectConstructor_Factory create(
+      javax.inject.Provider<Outer.Factory> factoryProvider) {
+    return new InjectConstructor_Factory(Providers.asDaggerProvider(factoryProvider));
+  }
+
   public static InjectConstructor_Factory create(Provider<Outer.Factory> factoryProvider) {
     return new InjectConstructor_Factory(factoryProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
index 41c6c72..c8d172b 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class SimpleType_Factory implements Factory<SimpleType> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();
+    static final SimpleType_Factory INSTANCE = new SimpleType_Factory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_samePackageNameCollision_test.InjectConstructor_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_samePackageNameCollision_test.InjectConstructor_Factory
index f65c9c5..2327674 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_samePackageNameCollision_test.InjectConstructor_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_samePackageNameCollision_test.InjectConstructor_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectConstructor_Factory implements Factory<InjectConstructor> {
   private final Provider<other.pkg.CommonName> otherPackageProvider;
@@ -38,6 +41,12 @@
   }
 
   public static InjectConstructor_Factory create(
+      javax.inject.Provider<other.pkg.CommonName> otherPackageProvider,
+      javax.inject.Provider<CommonName> samePackageProvider) {
+    return new InjectConstructor_Factory(Providers.asDaggerProvider(otherPackageProvider), Providers.asDaggerProvider(samePackageProvider));
+  }
+
+  public static InjectConstructor_Factory create(
       Provider<other.pkg.CommonName> otherPackageProvider,
       Provider<CommonName> samePackageProvider) {
     return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_simpleComponentWithNesting_test.OuterType_A_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_simpleComponentWithNesting_test.OuterType_A_Factory
index 424c614..b0c7a56 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_simpleComponentWithNesting_test.OuterType_A_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_simpleComponentWithNesting_test.OuterType_A_Factory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class OuterType_A_Factory implements Factory<OuterType.A> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final OuterType_A_Factory INSTANCE = new OuterType_A_Factory();
+    static final OuterType_A_Factory INSTANCE = new OuterType_A_Factory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_Factory
index 1f00f95..7771f5f 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata("test.FooBaseConstructorQualifier")
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FooBase_Factory implements Factory<FooBase> {
   private final Provider<Integer> iProvider;
@@ -43,6 +46,11 @@
     return instance;
   }
 
+  public static FooBase_Factory create(javax.inject.Provider<Integer> iProvider,
+      javax.inject.Provider<String> injectFieldProvider, javax.inject.Provider<Float> fProvider) {
+    return new FooBase_Factory(Providers.asDaggerProvider(iProvider), Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   public static FooBase_Factory create(Provider<Integer> iProvider,
       Provider<String> injectFieldProvider, Provider<Float> fProvider) {
     return new FooBase_Factory(iProvider, injectFieldProvider, fProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_MembersInjector b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_MembersInjector
index 5e865ff..be0404b 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.FooBase_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata({
     "test.FooBaseFieldQualifier",
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FooBase_MembersInjector implements MembersInjector<FooBase> {
   private final Provider<String> injectFieldProvider;
@@ -38,6 +41,11 @@
     return new FooBase_MembersInjector(injectFieldProvider, fProvider);
   }
 
+  public static MembersInjector<FooBase> create(javax.inject.Provider<String> injectFieldProvider,
+      javax.inject.Provider<Float> fProvider) {
+    return new FooBase_MembersInjector(Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   @Override
   public void injectMembers(FooBase instance) {
     injectInjectField(instance, injectFieldProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_Factory
index 48d9102..7b4c1d6 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata("test.FooConstructorQualifier")
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Foo_Factory implements Factory<Foo> {
   private final Provider<Integer> iProvider;
@@ -47,6 +50,12 @@
     return instance;
   }
 
+  public static Foo_Factory create(javax.inject.Provider<Integer> iProvider,
+      javax.inject.Provider<String> injectFieldProvider,
+      javax.inject.Provider<String> injectFieldProvider2, javax.inject.Provider<Float> fProvider) {
+    return new Foo_Factory(Providers.asDaggerProvider(iProvider), Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(injectFieldProvider2), Providers.asDaggerProvider(fProvider));
+  }
+
   public static Foo_Factory create(Provider<Integer> iProvider,
       Provider<String> injectFieldProvider, Provider<String> injectFieldProvider2,
       Provider<Float> fProvider) {
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_MembersInjector b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_MembersInjector
index 7485836..5352370 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testBaseClassQualifierMetadata_test.Foo_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata({
     "test.FooFieldQualifier",
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Foo_MembersInjector implements MembersInjector<Foo> {
   private final Provider<String> injectFieldProvider;
@@ -42,6 +45,11 @@
     return new Foo_MembersInjector(injectFieldProvider, injectFieldProvider2, fProvider);
   }
 
+  public static MembersInjector<Foo> create(javax.inject.Provider<String> injectFieldProvider,
+      javax.inject.Provider<String> injectFieldProvider2, javax.inject.Provider<Float> fProvider) {
+    return new Foo_MembersInjector(Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(injectFieldProvider2), Providers.asDaggerProvider(fProvider));
+  }
+
   @Override
   public void injectMembers(Foo instance) {
     FooBase_MembersInjector.injectInjectField(instance, injectFieldProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_Factory
index 2d100f6..4d0c734 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata({
@@ -22,7 +23,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class SomeBinding_Factory implements Factory<SomeBinding> {
   private final Provider<String> str1Provider;
@@ -49,6 +52,12 @@
     return instance;
   }
 
+  public static SomeBinding_Factory create(javax.inject.Provider<String> str1Provider,
+      javax.inject.Provider<String> str2Provider, javax.inject.Provider<String> injectFieldProvider,
+      javax.inject.Provider<Float> fProvider) {
+    return new SomeBinding_Factory(Providers.asDaggerProvider(str1Provider), Providers.asDaggerProvider(str2Provider), Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   public static SomeBinding_Factory create(Provider<String> str1Provider,
       Provider<String> str2Provider, Provider<String> injectFieldProvider,
       Provider<Float> fProvider) {
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_MembersInjector b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_MembersInjector
index a5707af..63ba30f 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testComplexQualifierMetadata_test.SomeBinding_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata({
     "test.QualifierWithValue",
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class SomeBinding_MembersInjector implements MembersInjector<SomeBinding> {
   private final Provider<String> injectFieldProvider;
@@ -39,6 +42,11 @@
     return new SomeBinding_MembersInjector(injectFieldProvider, fProvider);
   }
 
+  public static MembersInjector<SomeBinding> create(
+      javax.inject.Provider<String> injectFieldProvider, javax.inject.Provider<Float> fProvider) {
+    return new SomeBinding_MembersInjector(Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   @Override
   public void injectMembers(SomeBinding instance) {
     injectInjectField(instance, injectFieldProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_Factory
index 40690b3..441131f 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata("test.ConstructorParameterQualifier")
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class SomeBinding_Factory implements Factory<SomeBinding> {
   private final Provider<Double> dProvider;
@@ -43,6 +46,11 @@
     return instance;
   }
 
+  public static SomeBinding_Factory create(javax.inject.Provider<Double> dProvider,
+      javax.inject.Provider<String> injectFieldProvider, javax.inject.Provider<Float> fProvider) {
+    return new SomeBinding_Factory(Providers.asDaggerProvider(dProvider), Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   public static SomeBinding_Factory create(Provider<Double> dProvider,
       Provider<String> injectFieldProvider, Provider<Float> fProvider) {
     return new SomeBinding_Factory(dProvider, injectFieldProvider, fProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_MembersInjector b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_MembersInjector
index a8ca780..aa14719 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testQualifierMetadata_test.SomeBinding_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata({
     "test.FieldQualifier",
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class SomeBinding_MembersInjector implements MembersInjector<SomeBinding> {
   private final Provider<String> injectFieldProvider;
@@ -39,6 +42,11 @@
     return new SomeBinding_MembersInjector(injectFieldProvider, fProvider);
   }
 
+  public static MembersInjector<SomeBinding> create(
+      javax.inject.Provider<String> injectFieldProvider, javax.inject.Provider<Float> fProvider) {
+    return new SomeBinding_MembersInjector(Providers.asDaggerProvider(injectFieldProvider), Providers.asDaggerProvider(fProvider));
+  }
+
   @Override
   public void injectMembers(SomeBinding instance) {
     injectInjectField(instance, injectFieldProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadataWithCustomScope_test.ScopedBinding_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadataWithCustomScope_test.ScopedBinding_Factory
index d949bdd..d031232 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadataWithCustomScope_test.ScopedBinding_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadataWithCustomScope_test.ScopedBinding_Factory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ScopedBinding_Factory implements Factory<ScopedBinding> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final ScopedBinding_Factory INSTANCE = new ScopedBinding_Factory();
+    static final ScopedBinding_Factory INSTANCE = new ScopedBinding_Factory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadata_test.ScopedBinding_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadata_test.ScopedBinding_Factory
index 5682bb0..3368c1a 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadata_test.ScopedBinding_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_testScopedMetadata_test.ScopedBinding_Factory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ScopedBinding_Factory implements Factory<ScopedBinding> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final ScopedBinding_Factory INSTANCE = new ScopedBinding_Factory();
+    static final ScopedBinding_Factory INSTANCE = new ScopedBinding_Factory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_twoGenericTypes_test.GenericClass_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_twoGenericTypes_test.GenericClass_Factory
index 116df17..9c722dc 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_twoGenericTypes_test.GenericClass_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_twoGenericTypes_test.GenericClass_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {
   private final Provider<A> aProvider;
@@ -36,6 +39,11 @@
     return newInstance(aProvider.get(), bProvider.get());
   }
 
+  public static <A, B> GenericClass_Factory<A, B> create(javax.inject.Provider<A> aProvider,
+      javax.inject.Provider<B> bProvider) {
+    return new GenericClass_Factory<A, B>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   public static <A, B> GenericClass_Factory<A, B> create(Provider<A> aProvider,
       Provider<B> bProvider) {
     return new GenericClass_Factory<A, B>(aProvider, bProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_wildcardDependency_test.InjectConstructor_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_wildcardDependency_test.InjectConstructor_Factory
index 681a4b6..bdafd5f 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_wildcardDependency_test.InjectConstructor_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_wildcardDependency_test.InjectConstructor_Factory
@@ -2,11 +2,12 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectConstructor_Factory implements Factory<InjectConstructor> {
   private final Provider<List<?>> objectsProvider;
@@ -34,6 +37,10 @@
     return newInstance(objectsProvider.get());
   }
 
+  public static InjectConstructor_Factory create(javax.inject.Provider<List<?>> objectsProvider) {
+    return new InjectConstructor_Factory(Providers.asDaggerProvider(objectsProvider));
+  }
+
   public static InjectConstructor_Factory create(Provider<List<?>> objectsProvider) {
     return new InjectConstructor_Factory(objectsProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_DEFAULT_MODE_test.DaggerTestComponent
similarity index 61%
rename from javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
rename to javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_DEFAULT_MODE_test.DaggerTestComponent
index 01ffe86..7cbc139 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_DEFAULT_MODE_test.DaggerTestComponent
@@ -1,10 +1,10 @@
 package test;
 
+import com.google.common.collect.ImmutableMap;
 import dagger.internal.DaggerGenerated;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
+import dagger.internal.LazyClassKeyMap;
+import java.util.Map;
+import javax.annotation.processing.Generated;
 
 @DaggerGenerated
 @Generated(
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -42,22 +44,15 @@
   private static final class TestComponentImpl implements TestComponent {
     private final TestComponentImpl testComponentImpl = this;
 
-    private Provider<Foo> bindProvider;
-
     private TestComponentImpl() {
 
-      initialize();
 
     }
 
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.bindProvider = DoubleCheck.provider((Provider) FooImpl_Factory.create());
-    }
-
     @Override
-    public Foo getFoo() {
-      return bindProvider.get();
+    public Map<Class<?>, Integer> classKey() {
+      return LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(MapKeyBindingsModule_ClassKey_LazyMapKey.lazyClassKeyName, MapKeyBindingsModule.classKey(), MapKeyBindingsModule_ClassKey2_LazyMapKey.lazyClassKeyName, MapKeyBindingsModule.classKey2()));
     }
   }
 }
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_FAST_INIT_MODE_test.DaggerTestComponent
similarity index 61%
copy from javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
copy to javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_FAST_INIT_MODE_test.DaggerTestComponent
index 01ffe86..7cbc139 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_lazyClassKeySimilarQualifiedName_doesNotConflict_FAST_INIT_MODE_test.DaggerTestComponent
@@ -1,10 +1,10 @@
 package test;
 
+import com.google.common.collect.ImmutableMap;
 import dagger.internal.DaggerGenerated;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Provider;
-import javax.annotation.Generated;
-import other.FooImpl_Factory;
+import dagger.internal.LazyClassKeyMap;
+import java.util.Map;
+import javax.annotation.processing.Generated;
 
 @DaggerGenerated
 @Generated(
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -42,22 +44,15 @@
   private static final class TestComponentImpl implements TestComponent {
     private final TestComponentImpl testComponentImpl = this;
 
-    private Provider<Foo> bindProvider;
-
     private TestComponentImpl() {
 
-      initialize();
 
     }
 
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.bindProvider = DoubleCheck.provider((Provider) FooImpl_Factory.create());
-    }
-
     @Override
-    public Foo getFoo() {
-      return bindProvider.get();
+    public Map<Class<?>, Integer> classKey() {
+      return LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(MapKeyBindingsModule_ClassKey_LazyMapKey.lazyClassKeyName, MapKeyBindingsModule.classKey(), MapKeyBindingsModule_ClassKey2_LazyMapKey.lazyClassKeyName, MapKeyBindingsModule.classKey2()));
     }
   }
 }
+
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
index 63a07ab..929342a 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ClassKeyMapKey {
   @KeepFieldType
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
index 3e00ffd..b0115fc 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {
   private MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
index eff6a40..44f0045 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
@@ -2,7 +2,6 @@
 
 import com.google.common.collect.ImmutableMap;
 import dagger.internal.DaggerGenerated;
-import dagger.internal.IdentifierNameString;
 import dagger.internal.LazyClassKeyMap;
 import dagger.internal.MapFactory;
 import dagger.internal.Provider;
@@ -11,6 +10,7 @@
 import mapkeys.MapKeys;
 import mapkeys.MapModule;
 import mapkeys.MapModule_ClassKeyFactory;
+import mapkeys.MapModule_ClassKey_LazyMapKey;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueFactory;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleArrayValueFactory;
@@ -28,7 +28,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -66,13 +68,13 @@
 
     @SuppressWarnings("unchecked")
     private void initialize() {
-      this.mapOfClassOfAndIntegerProvider = LazyClassKeyMap.Factory.<Integer>of(MapFactory.<String, Integer>builder(1).put(LazyClassKeyProvider.mapkeys_MapKeys_Inaccessible, MapModule_ClassKeyFactory.create()).build());
+      this.mapOfClassOfAndIntegerProvider = LazyClassKeyMap.MapFactory.<Integer>of(MapFactory.<String, Integer>builder(1).put(MapModule_ClassKey_LazyMapKey.lazyClassKeyName, MapModule_ClassKeyFactory.create()).build());
       this.mapOfComplexKeyAndIntegerProvider = MapFactory.<MapKeys.ComplexKey, Integer>builder(3).put(MapModule_ComplexKeyWithInaccessibleValueMapKey.create(), MapModule_ComplexKeyWithInaccessibleValueFactory.create()).put(MapModule_ComplexKeyWithInaccessibleArrayValueMapKey.create(), MapModule_ComplexKeyWithInaccessibleArrayValueFactory.create()).put(MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey.create(), MapModule_ComplexKeyWithInaccessibleAnnotationValueFactory.create()).build();
     }
 
     @Override
     public Map<Class<?>, Integer> classKey() {
-      return LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(LazyClassKeyProvider.mapkeys_MapKeys_Inaccessible, MapModule.classKey()));
+      return LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(MapModule_ClassKey_LazyMapKey.lazyClassKeyName, MapModule.classKey()));
     }
 
     @Override
@@ -89,11 +91,6 @@
     public javax.inject.Provider<Map<MapKeys.ComplexKey, Integer>> complexKeyProvider() {
       return mapOfComplexKeyAndIntegerProvider;
     }
-
-    @IdentifierNameString
-    private static final class LazyClassKeyProvider {
-      static String mapkeys_MapKeys_Inaccessible = "mapkeys.MapKeys$Inaccessible";
-    }
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
index 63a07ab..929342a 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ClassKeyMapKey {
   @KeepFieldType
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
index 3e00ffd..b0115fc 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {
   private MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
index 478b010..363be57 100644
--- a/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/LazyClassKeyMapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
@@ -2,13 +2,13 @@
 
 import com.google.common.collect.ImmutableMap;
 import dagger.internal.DaggerGenerated;
-import dagger.internal.IdentifierNameString;
 import dagger.internal.LazyClassKeyMap;
 import dagger.internal.Provider;
 import java.util.Map;
 import javax.annotation.processing.Generated;
 import mapkeys.MapKeys;
 import mapkeys.MapModule;
+import mapkeys.MapModule_ClassKey_LazyMapKey;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleArrayValueMapKey;
 import mapkeys.MapModule_ComplexKeyWithInaccessibleValueMapKey;
@@ -23,7 +23,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -100,7 +102,7 @@
       public T get() {
         switch (id) {
           case 0: // java.util.Map<java.lang.Class<?>,java.lang.Integer> 
-          return (T) LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(LazyClassKeyProvider.mapkeys_MapKeys_Inaccessible, MapModule.classKey()));
+          return (T) LazyClassKeyMap.<Integer>of(ImmutableMap.<String, Integer>of(MapModule_ClassKey_LazyMapKey.lazyClassKeyName, MapModule.classKey()));
 
           case 1: // java.util.Map<mapkeys.MapKeys.ComplexKey,java.lang.Integer> 
           return (T) ImmutableMap.<MapKeys.ComplexKey, Integer>of(MapModule_ComplexKeyWithInaccessibleValueMapKey.create(), MapModule.complexKeyWithInaccessibleValue(), MapModule_ComplexKeyWithInaccessibleArrayValueMapKey.create(), MapModule.complexKeyWithInaccessibleArrayValue(), MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey.create(), MapModule.complexKeyWithInaccessibleAnnotationValue());
@@ -109,11 +111,6 @@
         }
       }
     }
-
-    @IdentifierNameString
-    private static final class LazyClassKeyProvider {
-      static String mapkeys_MapKeys_Inaccessible = "mapkeys.MapKeys$Inaccessible";
-    }
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_DEFAULT_MODE_test.DaggerTestComponent
index b348b61..602ccff 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_FAST_INIT_MODE_test.DaggerTestComponent
index b348b61..602ccff 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_injectMapWithoutMapBinding_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_DEFAULT_MODE_test.DaggerTestComponent
index dbffedd..6370b02 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_FAST_INIT_MODE_test.DaggerTestComponent
index 54f6250..ec0efd9 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithEnumKey_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -110,10 +112,10 @@
           case 0: // java.util.Map<test.PathEnum,javax.inject.Provider<test.Handler>> 
           return (T) ImmutableMap.<PathEnum, javax.inject.Provider<Handler>>of(PathEnum.ADMIN, testComponentImpl.provideAdminHandlerProvider, PathEnum.LOGIN, testComponentImpl.provideLoginHandlerProvider);
 
-          case 1: // java.util.Map<test.PathEnum,javax.inject.Provider<test.Handler>> test.MapModuleOne#provideAdminHandler 
+          case 1: // java.util.Map<test.PathEnum,test.Handler> test.MapModuleOne#provideAdminHandler 
           return (T) MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(testComponentImpl.mapModuleOne);
 
-          case 2: // java.util.Map<test.PathEnum,javax.inject.Provider<test.Handler>> test.MapModuleTwo#provideLoginHandler 
+          case 2: // java.util.Map<test.PathEnum,test.Handler> test.MapModuleTwo#provideLoginHandler 
           return (T) MapModuleTwo_ProvideLoginHandlerFactory.provideLoginHandler(testComponentImpl.mapModuleTwo);
 
           default: throw new AssertionError(id);
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
index 209220e..d66dad1 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ClassKeyMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ClassKeyMapKey {
   private MapModule_ClassKeyMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
index f65280b..4485b14 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {
   private MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
index 2b35d46..fd01938 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_DEFAULT_MODE_test.DaggerTestComponent
@@ -29,7 +29,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
index 209220e..d66dad1 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ClassKeyMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ClassKeyMapKey {
   private MapModule_ClassKeyMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
index f65280b..4485b14 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {
   private MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
index 2b35d46..fd01938 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithInaccessibleKeys_FAST_INIT_MODE_test.DaggerTestComponent
@@ -29,7 +29,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_DEFAULT_MODE_test.DaggerTestComponent
index e2d93ec..70573d2 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_FAST_INIT_MODE_test.DaggerTestComponent
index c3f0578..21caca8 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithNonProviderValue_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_DEFAULT_MODE_test.DaggerTestComponent
index cd24892..c8d2b01 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_FAST_INIT_MODE_test.DaggerTestComponent
index 47a7d8b..e497c98 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithStringKey_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -110,10 +112,10 @@
           case 0: // java.util.Map<java.lang.String,javax.inject.Provider<test.Handler>> 
           return (T) ImmutableMap.<String, javax.inject.Provider<Handler>>of("Admin", testComponentImpl.provideAdminHandlerProvider, "Login", testComponentImpl.provideLoginHandlerProvider);
 
-          case 1: // java.util.Map<java.lang.String,javax.inject.Provider<test.Handler>> test.MapModuleOne#provideAdminHandler 
+          case 1: // java.util.Map<java.lang.String,test.Handler> test.MapModuleOne#provideAdminHandler 
           return (T) MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(testComponentImpl.mapModuleOne);
 
-          case 2: // java.util.Map<java.lang.String,javax.inject.Provider<test.Handler>> test.MapModuleTwo#provideLoginHandler 
+          case 2: // java.util.Map<java.lang.String,test.Handler> test.MapModuleTwo#provideLoginHandler 
           return (T) MapModuleTwo_ProvideLoginHandlerFactory.provideLoginHandler(testComponentImpl.mapModuleTwo);
 
           default: throw new AssertionError(id);
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_DEFAULT_MODE_test.DaggerTestComponent
index bbba316..9674b0b 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_FAST_INIT_MODE_test.DaggerTestComponent
index d057b50..89a4c43 100644
--- a/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapBindingComponentProcessorTest_mapBindingsWithWrappedKey_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
index 37bbf79..175cd39 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
index 37bbf79..175cd39 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
index f47f081..dc4158c 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
index 0acd7f1..d24c78b 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -109,16 +111,16 @@
       @Override
       public T get() {
         switch (id) {
-          case 0: // java.util.Map<java.lang.Integer,javax.inject.Provider<java.lang.Integer>> test.MapModule#provideInt 
+          case 0: // java.util.Map<java.lang.Integer,java.lang.Integer> test.MapModule#provideInt 
           return (T) (Integer) MapModule.provideInt();
 
-          case 1: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong0 
+          case 1: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong0 
           return (T) (Long) MapModule.provideLong0();
 
-          case 2: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong1 
+          case 2: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong1 
           return (T) (Long) MapModule.provideLong1();
 
-          case 3: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong2 
+          case 3: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong2 
           return (T) (Long) MapModule.provideLong2();
 
           default: throw new AssertionError(id);
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
index 8ae5d82..0c598e4 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
index 8ae5d82..0c598e4 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
index f4f6564..13f9890 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
index f4f6564..13f9890 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
index 24c5619..3f40b31 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
index 24c5619..3f40b31 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
index 5520281..e00a7fa 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
index 12346c8..ffa1646 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_mapBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -91,13 +93,13 @@
       @Override
       public T get() {
         switch (id) {
-          case 0: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.SubcomponentMapModule#provideLong3 
+          case 0: // java.util.Map<java.lang.Long,java.lang.Long> test.SubcomponentMapModule#provideLong3 
           return (T) (Long) SubcomponentMapModule.provideLong3();
 
-          case 1: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.SubcomponentMapModule#provideLong4 
+          case 1: // java.util.Map<java.lang.Long,java.lang.Long> test.SubcomponentMapModule#provideLong4 
           return (T) (Long) SubcomponentMapModule.provideLong4();
 
-          case 2: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.SubcomponentMapModule#provideLong5 
+          case 2: // java.util.Map<java.lang.Long,java.lang.Long> test.SubcomponentMapModule#provideLong5 
           return (T) (Long) SubcomponentMapModule.provideLong5();
 
           default: throw new AssertionError(id);
@@ -180,16 +182,16 @@
       @Override
       public T get() {
         switch (id) {
-          case 0: // java.util.Map<java.lang.Integer,javax.inject.Provider<java.lang.Integer>> test.MapModule#provideInt 
+          case 0: // java.util.Map<java.lang.Integer,java.lang.Integer> test.MapModule#provideInt 
           return (T) (Integer) MapModule.provideInt();
 
-          case 1: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong0 
+          case 1: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong0 
           return (T) (Long) MapModule.provideLong0();
 
-          case 2: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong1 
+          case 2: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong1 
           return (T) (Long) MapModule.provideLong1();
 
-          case 3: // java.util.Map<java.lang.Long,javax.inject.Provider<java.lang.Long>> test.MapModule#provideLong2 
+          case 3: // java.util.Map<java.lang.Long,java.lang.Long> test.MapModule#provideLong2 
           return (T) (Long) MapModule.provideLong2();
 
           default: throw new AssertionError(id);
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
index dc29708..7d54ce0 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
index dc29708..7d54ce0 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
index 0ac6e9f..aad298b 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
index 0ac6e9f..aad298b 100644
--- a/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/MapRequestRepresentationWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_other.Inaccessible_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_other.Inaccessible_MembersInjector
index cc45f79..f051e2a 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_other.Inaccessible_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_other.Inaccessible_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Inaccessible_MembersInjector implements MembersInjector<Inaccessible> {
   private final Provider<Foo> fooProvider;
@@ -35,6 +38,11 @@
     return new Inaccessible_MembersInjector(fooProvider, fooProvider2);
   }
 
+  public static MembersInjector<Inaccessible> create(javax.inject.Provider<Foo> fooProvider,
+      javax.inject.Provider<Foo> fooProvider2) {
+    return new Inaccessible_MembersInjector(Providers.asDaggerProvider(fooProvider), Providers.asDaggerProvider(fooProvider2));
+  }
+
   @Override
   public void injectMembers(Inaccessible instance) {
     injectFoo(instance, fooProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_test.DaggerTestComponent
index 5f232b1..63a1650 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_DEFAULT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_other.Inaccessible_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_other.Inaccessible_MembersInjector
index cc45f79..f051e2a 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_other.Inaccessible_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_other.Inaccessible_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Inaccessible_MembersInjector implements MembersInjector<Inaccessible> {
   private final Provider<Foo> fooProvider;
@@ -35,6 +38,11 @@
     return new Inaccessible_MembersInjector(fooProvider, fooProvider2);
   }
 
+  public static MembersInjector<Inaccessible> create(javax.inject.Provider<Foo> fooProvider,
+      javax.inject.Provider<Foo> fooProvider2) {
+    return new Inaccessible_MembersInjector(Providers.asDaggerProvider(fooProvider), Providers.asDaggerProvider(fooProvider2));
+  }
+
   @Override
   public void injectMembers(Inaccessible instance) {
     injectFoo(instance, fooProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_test.DaggerTestComponent
index 5f232b1..63a1650 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibility_FAST_INIT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
index c17dea0..7a20d14 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_DEFAULT_MODE_test.DaggerTestComponent
@@ -21,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
index 854a429..bc1ffbe 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_accessibleRawType_ofInaccessibleType_FAST_INIT_MODE_test.DaggerTestComponent
@@ -21,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_DEFAULT_MODE_test.OuterType_B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_DEFAULT_MODE_test.OuterType_B_MembersInjector
index 5b4932f..d2b3141 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_DEFAULT_MODE_test.OuterType_B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_DEFAULT_MODE_test.OuterType_B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class OuterType_B_MembersInjector implements MembersInjector<OuterType.B> {
   private final Provider<OuterType.A> aProvider;
@@ -31,6 +34,10 @@
     return new OuterType_B_MembersInjector(aProvider);
   }
 
+  public static MembersInjector<OuterType.B> create(javax.inject.Provider<OuterType.A> aProvider) {
+    return new OuterType_B_MembersInjector(Providers.asDaggerProvider(aProvider));
+  }
+
   @Override
   public void injectMembers(OuterType.B instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
index 5b4932f..d2b3141 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class OuterType_B_MembersInjector implements MembersInjector<OuterType.B> {
   private final Provider<OuterType.A> aProvider;
@@ -31,6 +34,10 @@
     return new OuterType_B_MembersInjector(aProvider);
   }
 
+  public static MembersInjector<OuterType.B> create(javax.inject.Provider<OuterType.A> aProvider) {
+    return new OuterType_B_MembersInjector(Providers.asDaggerProvider(aProvider));
+  }
+
   @Override
   public void injectMembers(OuterType.B instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_DEFAULT_MODE_test.GenericClass_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_DEFAULT_MODE_test.GenericClass_MembersInjector
index 70415a8..5c1efb9 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_DEFAULT_MODE_test.GenericClass_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_DEFAULT_MODE_test.GenericClass_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_MembersInjector<A, B> implements MembersInjector<GenericClass<A, B>> {
   private final Provider<A> aProvider;
@@ -35,6 +38,11 @@
     return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);
   }
 
+  public static <A, B> MembersInjector<GenericClass<A, B>> create(
+      javax.inject.Provider<A> aProvider, javax.inject.Provider<B> bProvider) {
+    return new GenericClass_MembersInjector<A, B>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   @Override
   public void injectMembers(GenericClass<A, B> instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_FAST_INIT_MODE_test.GenericClass_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_FAST_INIT_MODE_test.GenericClass_MembersInjector
index 70415a8..5c1efb9 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_FAST_INIT_MODE_test.GenericClass_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldAndMethodGenerics_FAST_INIT_MODE_test.GenericClass_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class GenericClass_MembersInjector<A, B> implements MembersInjector<GenericClass<A, B>> {
   private final Provider<A> aProvider;
@@ -35,6 +38,11 @@
     return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);
   }
 
+  public static <A, B> MembersInjector<GenericClass<A, B>> create(
+      javax.inject.Provider<A> aProvider, javax.inject.Provider<B> bProvider) {
+    return new GenericClass_MembersInjector<A, B>(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   @Override
   public void injectMembers(GenericClass<A, B> instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_DEFAULT_MODE_test.Child_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_DEFAULT_MODE_test.Child_MembersInjector
index 2f69706..abd1246 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_DEFAULT_MODE_test.Child_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_DEFAULT_MODE_test.Child_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Child_MembersInjector implements MembersInjector<Child> {
   private final Provider<Foo> objectProvider;
@@ -35,6 +38,11 @@
     return new Child_MembersInjector(objectProvider, objectProvider2);
   }
 
+  public static MembersInjector<Child> create(javax.inject.Provider<Foo> objectProvider,
+      javax.inject.Provider<Bar> objectProvider2) {
+    return new Child_MembersInjector(Providers.asDaggerProvider(objectProvider), Providers.asDaggerProvider(objectProvider2));
+  }
+
   @Override
   public void injectMembers(Child instance) {
     Parent_MembersInjector.injectObject(instance, objectProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_FAST_INIT_MODE_test.Child_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_FAST_INIT_MODE_test.Child_MembersInjector
index 2f69706..abd1246 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_FAST_INIT_MODE_test.Child_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionForShadowedMember_FAST_INIT_MODE_test.Child_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Child_MembersInjector implements MembersInjector<Child> {
   private final Provider<Foo> objectProvider;
@@ -35,6 +38,11 @@
     return new Child_MembersInjector(objectProvider, objectProvider2);
   }
 
+  public static MembersInjector<Child> create(javax.inject.Provider<Foo> objectProvider,
+      javax.inject.Provider<Bar> objectProvider2) {
+    return new Child_MembersInjector(Providers.asDaggerProvider(objectProvider), Providers.asDaggerProvider(objectProvider2));
+  }
+
   @Override
   public void injectMembers(Child instance) {
     Parent_MembersInjector.injectObject(instance, objectProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_DEFAULT_MODE_test.FieldInjectionWithQualifier_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_DEFAULT_MODE_test.FieldInjectionWithQualifier_MembersInjector
index 46faeb8..e5f2745 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_DEFAULT_MODE_test.FieldInjectionWithQualifier_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_DEFAULT_MODE_test.FieldInjectionWithQualifier_MembersInjector
@@ -3,10 +3,11 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
 import javax.inject.Named;
-import javax.inject.Provider;
 
 @QualifierMetadata("javax.inject.Named")
 @DaggerGenerated
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FieldInjectionWithQualifier_MembersInjector implements MembersInjector<FieldInjectionWithQualifier> {
   private final Provider<String> aProvider;
@@ -37,6 +40,11 @@
     return new FieldInjectionWithQualifier_MembersInjector(aProvider, bProvider);
   }
 
+  public static MembersInjector<FieldInjectionWithQualifier> create(
+      javax.inject.Provider<String> aProvider, javax.inject.Provider<String> bProvider) {
+    return new FieldInjectionWithQualifier_MembersInjector(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   @Override
   public void injectMembers(FieldInjectionWithQualifier instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_FAST_INIT_MODE_test.FieldInjectionWithQualifier_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_FAST_INIT_MODE_test.FieldInjectionWithQualifier_MembersInjector
index 46faeb8..e5f2745 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_FAST_INIT_MODE_test.FieldInjectionWithQualifier_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjectionWithQualifier_FAST_INIT_MODE_test.FieldInjectionWithQualifier_MembersInjector
@@ -3,10 +3,11 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
 import javax.inject.Named;
-import javax.inject.Provider;
 
 @QualifierMetadata("javax.inject.Named")
 @DaggerGenerated
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FieldInjectionWithQualifier_MembersInjector implements MembersInjector<FieldInjectionWithQualifier> {
   private final Provider<String> aProvider;
@@ -37,6 +40,11 @@
     return new FieldInjectionWithQualifier_MembersInjector(aProvider, bProvider);
   }
 
+  public static MembersInjector<FieldInjectionWithQualifier> create(
+      javax.inject.Provider<String> aProvider, javax.inject.Provider<String> bProvider) {
+    return new FieldInjectionWithQualifier_MembersInjector(Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider));
+  }
+
   @Override
   public void injectMembers(FieldInjectionWithQualifier instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
index b0af865..ebb9deb 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
@@ -5,9 +5,10 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.DoubleCheck;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
   private final Provider<String> stringProvider;
@@ -41,6 +44,12 @@
     return new FieldInjection_MembersInjector(stringProvider, stringProvider2, stringProvider3);
   }
 
+  public static MembersInjector<FieldInjection> create(javax.inject.Provider<String> stringProvider,
+      javax.inject.Provider<String> stringProvider2,
+      javax.inject.Provider<String> stringProvider3) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(stringProvider2), Providers.asDaggerProvider(stringProvider3));
+  }
+
   @Override
   public void injectMembers(FieldInjection instance) {
     injectString(instance, stringProvider.get());
@@ -59,7 +68,8 @@
   }
 
   @InjectedFieldSignature("test.FieldInjection.stringProvider")
-  public static void injectStringProvider(Object instance, Provider<String> stringProvider) {
+  public static void injectStringProvider(Object instance,
+      javax.inject.Provider<String> stringProvider) {
     ((FieldInjection) instance).stringProvider = stringProvider;
   }
 }
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
index b0af865..ebb9deb 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_fieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
@@ -5,9 +5,10 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.DoubleCheck;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
   private final Provider<String> stringProvider;
@@ -41,6 +44,12 @@
     return new FieldInjection_MembersInjector(stringProvider, stringProvider2, stringProvider3);
   }
 
+  public static MembersInjector<FieldInjection> create(javax.inject.Provider<String> stringProvider,
+      javax.inject.Provider<String> stringProvider2,
+      javax.inject.Provider<String> stringProvider3) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(stringProvider2), Providers.asDaggerProvider(stringProvider3));
+  }
+
   @Override
   public void injectMembers(FieldInjection instance) {
     injectString(instance, stringProvider.get());
@@ -59,7 +68,8 @@
   }
 
   @InjectedFieldSignature("test.FieldInjection.stringProvider")
-  public static void injectStringProvider(Object instance, Provider<String> stringProvider) {
+  public static void injectStringProvider(Object instance,
+      javax.inject.Provider<String> stringProvider) {
     ((FieldInjection) instance).stringProvider = stringProvider;
   }
 }
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector
index 0c67f59..34fcdd4 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class AllInjections_MembersInjector implements MembersInjector<AllInjections> {
   private final Provider<String> sProvider;
@@ -35,6 +38,11 @@
     return new AllInjections_MembersInjector(sProvider, sProvider2);
   }
 
+  public static MembersInjector<AllInjections> create(javax.inject.Provider<String> sProvider,
+      javax.inject.Provider<String> sProvider2) {
+    return new AllInjections_MembersInjector(Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(sProvider2));
+  }
+
   @Override
   public void injectMembers(AllInjections instance) {
     injectS(instance, sProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_FAST_INIT_MODE_test.AllInjections_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_FAST_INIT_MODE_test.AllInjections_MembersInjector
index 0c67f59..34fcdd4 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_FAST_INIT_MODE_test.AllInjections_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectConstructorAndMembersInjection_FAST_INIT_MODE_test.AllInjections_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class AllInjections_MembersInjector implements MembersInjector<AllInjections> {
   private final Provider<String> sProvider;
@@ -35,6 +38,11 @@
     return new AllInjections_MembersInjector(sProvider, sProvider2);
   }
 
+  public static MembersInjector<AllInjections> create(javax.inject.Provider<String> sProvider,
+      javax.inject.Provider<String> sProvider2) {
+    return new AllInjections_MembersInjector(Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(sProvider2));
+  }
+
   @Override
   public void injectMembers(AllInjections instance) {
     injectS(instance, sProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_Factory b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_Factory
index b63c408..458ce48 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_Factory
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectedType_Factory implements Factory<InjectedType> {
   private final Provider<Integer> primitiveIntProvider;
@@ -40,6 +43,11 @@
     return instance;
   }
 
+  public static InjectedType_Factory create(javax.inject.Provider<Integer> primitiveIntProvider,
+      javax.inject.Provider<Integer> boxedIntProvider) {
+    return new InjectedType_Factory(Providers.asDaggerProvider(primitiveIntProvider), Providers.asDaggerProvider(boxedIntProvider));
+  }
+
   public static InjectedType_Factory create(Provider<Integer> primitiveIntProvider,
       Provider<Integer> boxedIntProvider) {
     return new InjectedType_Factory(primitiveIntProvider, boxedIntProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_MembersInjector
index f288697..cc58fd5 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_DEFAULT_MODE_test.InjectedType_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectedType_MembersInjector implements MembersInjector<InjectedType> {
   private final Provider<Integer> primitiveIntProvider;
@@ -36,6 +39,12 @@
     return new InjectedType_MembersInjector(primitiveIntProvider, boxedIntProvider);
   }
 
+  public static MembersInjector<InjectedType> create(
+      javax.inject.Provider<Integer> primitiveIntProvider,
+      javax.inject.Provider<Integer> boxedIntProvider) {
+    return new InjectedType_MembersInjector(Providers.asDaggerProvider(primitiveIntProvider), Providers.asDaggerProvider(boxedIntProvider));
+  }
+
   @Override
   public void injectMembers(InjectedType instance) {
     injectPrimitiveInt(instance, primitiveIntProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_Factory b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_Factory
index b63c408..458ce48 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_Factory
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_Factory
@@ -2,10 +2,11 @@
 
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectedType_Factory implements Factory<InjectedType> {
   private final Provider<Integer> primitiveIntProvider;
@@ -40,6 +43,11 @@
     return instance;
   }
 
+  public static InjectedType_Factory create(javax.inject.Provider<Integer> primitiveIntProvider,
+      javax.inject.Provider<Integer> boxedIntProvider) {
+    return new InjectedType_Factory(Providers.asDaggerProvider(primitiveIntProvider), Providers.asDaggerProvider(boxedIntProvider));
+  }
+
   public static InjectedType_Factory create(Provider<Integer> primitiveIntProvider,
       Provider<Integer> boxedIntProvider) {
     return new InjectedType_Factory(primitiveIntProvider, boxedIntProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_MembersInjector
index f288697..cc58fd5 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_injectsPrimitive_FAST_INIT_MODE_test.InjectedType_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class InjectedType_MembersInjector implements MembersInjector<InjectedType> {
   private final Provider<Integer> primitiveIntProvider;
@@ -36,6 +39,12 @@
     return new InjectedType_MembersInjector(primitiveIntProvider, boxedIntProvider);
   }
 
+  public static MembersInjector<InjectedType> create(
+      javax.inject.Provider<Integer> primitiveIntProvider,
+      javax.inject.Provider<Integer> boxedIntProvider) {
+    return new InjectedType_MembersInjector(Providers.asDaggerProvider(primitiveIntProvider), Providers.asDaggerProvider(boxedIntProvider));
+  }
+
   @Override
   public void injectMembers(InjectedType instance) {
     injectPrimitiveInt(instance, primitiveIntProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_DEFAULT_MODE_test.MyClass_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_DEFAULT_MODE_test.MyClass_MembersInjector
new file mode 100644
index 0000000..17f220a
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_DEFAULT_MODE_test.MyClass_MembersInjector
@@ -0,0 +1,65 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+import org.jetbrains.annotations.Nullable;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class MyClass_MembersInjector implements MembersInjector<MyClass> {
+  private final Provider<String> nullableStringProvider;
+
+  private final Provider<Object> nullableObjectProvider;
+
+  public MyClass_MembersInjector(Provider<String> nullableStringProvider,
+      Provider<Object> nullableObjectProvider) {
+    this.nullableStringProvider = nullableStringProvider;
+    this.nullableObjectProvider = nullableObjectProvider;
+  }
+
+  public static MembersInjector<MyClass> create(Provider<String> nullableStringProvider,
+      Provider<Object> nullableObjectProvider) {
+    return new MyClass_MembersInjector(nullableStringProvider, nullableObjectProvider);
+  }
+
+  public static MembersInjector<MyClass> create(
+      javax.inject.Provider<String> nullableStringProvider,
+      javax.inject.Provider<Object> nullableObjectProvider) {
+    return new MyClass_MembersInjector(Providers.asDaggerProvider(nullableStringProvider), Providers.asDaggerProvider(nullableObjectProvider));
+  }
+
+  @Override
+  public void injectMembers(MyClass instance) {
+    injectNullableString(instance, nullableStringProvider.get());
+    injectNullableObject(instance, nullableObjectProvider.get());
+  }
+
+  @InjectedFieldSignature("test.MyClass.nullableString")
+  public static void injectNullableString(MyClass instance, @Nullable String nullableString) {
+    instance.nullableString = nullableString;
+  }
+
+  @InjectedFieldSignature("test.MyClass.nullableObject")
+  public static void injectNullableObject(MyClass instance, @Nullable Object nullableObject) {
+    instance.nullableObject = nullableObject;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_FAST_INIT_MODE_test.MyClass_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_FAST_INIT_MODE_test.MyClass_MembersInjector
new file mode 100644
index 0000000..17f220a
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_kotlinNullableFieldInjection_FAST_INIT_MODE_test.MyClass_MembersInjector
@@ -0,0 +1,65 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+import org.jetbrains.annotations.Nullable;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class MyClass_MembersInjector implements MembersInjector<MyClass> {
+  private final Provider<String> nullableStringProvider;
+
+  private final Provider<Object> nullableObjectProvider;
+
+  public MyClass_MembersInjector(Provider<String> nullableStringProvider,
+      Provider<Object> nullableObjectProvider) {
+    this.nullableStringProvider = nullableStringProvider;
+    this.nullableObjectProvider = nullableObjectProvider;
+  }
+
+  public static MembersInjector<MyClass> create(Provider<String> nullableStringProvider,
+      Provider<Object> nullableObjectProvider) {
+    return new MyClass_MembersInjector(nullableStringProvider, nullableObjectProvider);
+  }
+
+  public static MembersInjector<MyClass> create(
+      javax.inject.Provider<String> nullableStringProvider,
+      javax.inject.Provider<Object> nullableObjectProvider) {
+    return new MyClass_MembersInjector(Providers.asDaggerProvider(nullableStringProvider), Providers.asDaggerProvider(nullableObjectProvider));
+  }
+
+  @Override
+  public void injectMembers(MyClass instance) {
+    injectNullableString(instance, nullableStringProvider.get());
+    injectNullableObject(instance, nullableObjectProvider.get());
+  }
+
+  @InjectedFieldSignature("test.MyClass.nullableString")
+  public static void injectNullableString(MyClass instance, @Nullable String nullableString) {
+    instance.nullableString = nullableString;
+  }
+
+  @InjectedFieldSignature("test.MyClass.nullableObject")
+  public static void injectNullableObject(MyClass instance, @Nullable Object nullableObject) {
+    instance.nullableObject = nullableObject;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_DEFAULT_MODE_test.MethodInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_DEFAULT_MODE_test.MethodInjection_MembersInjector
index 9d11248..1b1e71f 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_DEFAULT_MODE_test.MethodInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_DEFAULT_MODE_test.MethodInjection_MembersInjector
@@ -4,9 +4,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.DoubleCheck;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MethodInjection_MembersInjector implements MembersInjector<MethodInjection> {
   private final Provider<String> stringProvider;
@@ -45,6 +48,13 @@
     return new MethodInjection_MembersInjector(stringProvider, stringProvider2, stringProvider3, stringProvider4);
   }
 
+  public static MembersInjector<MethodInjection> create(
+      javax.inject.Provider<String> stringProvider, javax.inject.Provider<String> stringProvider2,
+      javax.inject.Provider<String> stringProvider3,
+      javax.inject.Provider<String> stringProvider4) {
+    return new MethodInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(stringProvider2), Providers.asDaggerProvider(stringProvider3), Providers.asDaggerProvider(stringProvider4));
+  }
+
   @Override
   public void injectMembers(MethodInjection instance) {
     injectNoArgs(instance);
@@ -61,7 +71,7 @@
   }
 
   public static void injectManyArgs(Object instance, String string, Lazy<String> lazyString,
-      Provider<String> stringProvider) {
+      javax.inject.Provider<String> stringProvider) {
     ((MethodInjection) instance).manyArgs(string, lazyString, stringProvider);
   }
 }
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_FAST_INIT_MODE_test.MethodInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_FAST_INIT_MODE_test.MethodInjection_MembersInjector
index 9d11248..1b1e71f 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_FAST_INIT_MODE_test.MethodInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_methodInjection_FAST_INIT_MODE_test.MethodInjection_MembersInjector
@@ -4,9 +4,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.DoubleCheck;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -19,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MethodInjection_MembersInjector implements MembersInjector<MethodInjection> {
   private final Provider<String> stringProvider;
@@ -45,6 +48,13 @@
     return new MethodInjection_MembersInjector(stringProvider, stringProvider2, stringProvider3, stringProvider4);
   }
 
+  public static MembersInjector<MethodInjection> create(
+      javax.inject.Provider<String> stringProvider, javax.inject.Provider<String> stringProvider2,
+      javax.inject.Provider<String> stringProvider3,
+      javax.inject.Provider<String> stringProvider4) {
+    return new MethodInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(stringProvider2), Providers.asDaggerProvider(stringProvider3), Providers.asDaggerProvider(stringProvider4));
+  }
+
   @Override
   public void injectMembers(MethodInjection instance) {
     injectNoArgs(instance);
@@ -61,7 +71,7 @@
   }
 
   public static void injectManyArgs(Object instance, String string, Lazy<String> lazyString,
-      Provider<String> stringProvider) {
+      javax.inject.Provider<String> stringProvider) {
     ((MethodInjection) instance).manyArgs(string, lazyString, stringProvider);
   }
 }
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.A_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.A_MembersInjector
index 86589c7..5158593 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.A_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.A_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class A_MembersInjector implements MembersInjector<A> {
   private final Provider<String> valueCProvider;
@@ -35,6 +38,11 @@
     return new A_MembersInjector(valueCProvider, valueAProvider);
   }
 
+  public static MembersInjector<A> create(javax.inject.Provider<String> valueCProvider,
+      javax.inject.Provider<String> valueAProvider) {
+    return new A_MembersInjector(Providers.asDaggerProvider(valueCProvider), Providers.asDaggerProvider(valueAProvider));
+  }
+
   @Override
   public void injectMembers(A instance) {
     C_MembersInjector.injectValueC(instance, valueCProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.C_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.C_MembersInjector
index 9c18178..8fc09d0 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.C_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_DEFAULT_MODE_test.C_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class C_MembersInjector implements MembersInjector<C> {
   private final Provider<String> valueCProvider;
@@ -31,6 +34,10 @@
     return new C_MembersInjector(valueCProvider);
   }
 
+  public static MembersInjector<C> create(javax.inject.Provider<String> valueCProvider) {
+    return new C_MembersInjector(Providers.asDaggerProvider(valueCProvider));
+  }
+
   @Override
   public void injectMembers(C instance) {
     injectValueC(instance, valueCProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.A_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
index 86589c7..5158593 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class A_MembersInjector implements MembersInjector<A> {
   private final Provider<String> valueCProvider;
@@ -35,6 +38,11 @@
     return new A_MembersInjector(valueCProvider, valueAProvider);
   }
 
+  public static MembersInjector<A> create(javax.inject.Provider<String> valueCProvider,
+      javax.inject.Provider<String> valueAProvider) {
+    return new A_MembersInjector(Providers.asDaggerProvider(valueCProvider), Providers.asDaggerProvider(valueAProvider));
+  }
+
   @Override
   public void injectMembers(A instance) {
     C_MembersInjector.injectValueC(instance, valueCProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.C_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.C_MembersInjector
index 9c18178..8fc09d0 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.C_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_middleClassNoFieldInjection_FAST_INIT_MODE_test.C_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class C_MembersInjector implements MembersInjector<C> {
   private final Provider<String> valueCProvider;
@@ -31,6 +34,10 @@
     return new C_MembersInjector(valueCProvider);
   }
 
+  public static MembersInjector<C> create(javax.inject.Provider<String> valueCProvider) {
+    return new C_MembersInjector(Providers.asDaggerProvider(valueCProvider));
+  }
+
   @Override
   public void injectMembers(C instance) {
     injectValueC(instance, valueCProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_DEFAULT_MODE_test.MixedMemberInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_DEFAULT_MODE_test.MixedMemberInjection_MembersInjector
index ba590b8..c968dd6 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_DEFAULT_MODE_test.MixedMemberInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_DEFAULT_MODE_test.MixedMemberInjection_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MixedMemberInjection_MembersInjector implements MembersInjector<MixedMemberInjection> {
   private final Provider<String> stringProvider;
@@ -42,6 +45,12 @@
     return new MixedMemberInjection_MembersInjector(stringProvider, objectProvider, sProvider, oProvider);
   }
 
+  public static MembersInjector<MixedMemberInjection> create(
+      javax.inject.Provider<String> stringProvider, javax.inject.Provider<Object> objectProvider,
+      javax.inject.Provider<String> sProvider, javax.inject.Provider<Object> oProvider) {
+    return new MixedMemberInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(objectProvider), Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(oProvider));
+  }
+
   @Override
   public void injectMembers(MixedMemberInjection instance) {
     injectString(instance, stringProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_FAST_INIT_MODE_test.MixedMemberInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_FAST_INIT_MODE_test.MixedMemberInjection_MembersInjector
index ba590b8..c968dd6 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_FAST_INIT_MODE_test.MixedMemberInjection_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_mixedMemberInjection_FAST_INIT_MODE_test.MixedMemberInjection_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MixedMemberInjection_MembersInjector implements MembersInjector<MixedMemberInjection> {
   private final Provider<String> stringProvider;
@@ -42,6 +45,12 @@
     return new MixedMemberInjection_MembersInjector(stringProvider, objectProvider, sProvider, oProvider);
   }
 
+  public static MembersInjector<MixedMemberInjection> create(
+      javax.inject.Provider<String> stringProvider, javax.inject.Provider<Object> objectProvider,
+      javax.inject.Provider<String> sProvider, javax.inject.Provider<Object> oProvider) {
+    return new MixedMemberInjection_MembersInjector(Providers.asDaggerProvider(stringProvider), Providers.asDaggerProvider(objectProvider), Providers.asDaggerProvider(sProvider), Providers.asDaggerProvider(oProvider));
+  }
+
   @Override
   public void injectMembers(MixedMemberInjection instance) {
     injectString(instance, stringProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
new file mode 100644
index 0000000..23ab444
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
@@ -0,0 +1,52 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
+  private final Provider<String> stringProvider;
+
+  public FieldInjection_MembersInjector(Provider<String> stringProvider) {
+    this.stringProvider = stringProvider;
+  }
+
+  public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(stringProvider);
+  }
+
+  public static MembersInjector<FieldInjection> create(
+      javax.inject.Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider));
+  }
+
+  @Override
+  public void injectMembers(FieldInjection instance) {
+    injectString(instance, stringProvider.get());
+  }
+
+  @InjectedFieldSignature("test.FieldInjection.string")
+  public static void injectString(Object instance, @Nullable String string) {
+    ((FieldInjection) instance).string = string;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
new file mode 100644
index 0000000..23ab444
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_nonTypeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
@@ -0,0 +1,52 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
+  private final Provider<String> stringProvider;
+
+  public FieldInjection_MembersInjector(Provider<String> stringProvider) {
+    this.stringProvider = stringProvider;
+  }
+
+  public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(stringProvider);
+  }
+
+  public static MembersInjector<FieldInjection> create(
+      javax.inject.Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider));
+  }
+
+  @Override
+  public void injectMembers(FieldInjection instance) {
+    injectString(instance, stringProvider.get());
+  }
+
+  @InjectedFieldSignature("test.FieldInjection.string")
+  public static void injectString(Object instance, @Nullable String string) {
+    ((FieldInjection) instance).string = string;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_DEFAULT_MODE_test.DaggerTestComponent
index 88e7fa5..c957ad7 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_FAST_INIT_MODE_test.DaggerTestComponent
index 88e7fa5..c957ad7 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_injectedMembersInSupertype_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_DEFAULT_MODE_test.DaggerTestComponent
index c4c4b07..b2fc405 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_DEFAULT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_FAST_INIT_MODE_test.DaggerTestComponent
index c4c4b07..b2fc405 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_parentClass_noInjectedMembers_FAST_INIT_MODE_test.DaggerTestComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_DEFAULT_MODE_test.DaggerTestComponent
index 04a4131..8b5855e 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_DEFAULT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_FAST_INIT_MODE_test.DaggerTestComponent
index 04a4131..8b5855e 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_publicSupertypeHiddenSubtype_FAST_INIT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_DEFAULT_MODE_test.OuterType_B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_DEFAULT_MODE_test.OuterType_B_MembersInjector
index 5b4932f..d2b3141 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_DEFAULT_MODE_test.OuterType_B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_DEFAULT_MODE_test.OuterType_B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class OuterType_B_MembersInjector implements MembersInjector<OuterType.B> {
   private final Provider<OuterType.A> aProvider;
@@ -31,6 +34,10 @@
     return new OuterType_B_MembersInjector(aProvider);
   }
 
+  public static MembersInjector<OuterType.B> create(javax.inject.Provider<OuterType.A> aProvider) {
+    return new OuterType_B_MembersInjector(Providers.asDaggerProvider(aProvider));
+  }
+
   @Override
   public void injectMembers(OuterType.B instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_FAST_INIT_MODE_test.OuterType_B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_FAST_INIT_MODE_test.OuterType_B_MembersInjector
index 5b4932f..d2b3141 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_FAST_INIT_MODE_test.OuterType_B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_simpleComponentWithNesting_FAST_INIT_MODE_test.OuterType_B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class OuterType_B_MembersInjector implements MembersInjector<OuterType.B> {
   private final Provider<OuterType.A> aProvider;
@@ -31,6 +34,10 @@
     return new OuterType_B_MembersInjector(aProvider);
   }
 
+  public static MembersInjector<OuterType.B> create(javax.inject.Provider<OuterType.A> aProvider) {
+    return new OuterType_B_MembersInjector(Providers.asDaggerProvider(aProvider));
+  }
+
   @Override
   public void injectMembers(OuterType.B instance) {
     injectA(instance, aProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_DEFAULT_MODE_test.Child_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_DEFAULT_MODE_test.Child_MembersInjector
index 6040966..e744215 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_DEFAULT_MODE_test.Child_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_DEFAULT_MODE_test.Child_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Child_MembersInjector<T> implements MembersInjector<Child<T>> {
   private final Provider<T> xProvider;
@@ -45,6 +48,12 @@
     return new Child_MembersInjector<T>(xProvider, yProvider, a2Provider, aProvider, tProvider);
   }
 
+  public static <T> MembersInjector<Child<T>> create(javax.inject.Provider<T> xProvider,
+      javax.inject.Provider<A> yProvider, javax.inject.Provider<A2> a2Provider,
+      javax.inject.Provider<A> aProvider, javax.inject.Provider<T> tProvider) {
+    return new Child_MembersInjector<T>(Providers.asDaggerProvider(xProvider), Providers.asDaggerProvider(yProvider), Providers.asDaggerProvider(a2Provider), Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(tProvider));
+  }
+
   @Override
   public void injectMembers(Child<T> instance) {
     Parent_MembersInjector.injectX(instance, xProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_FAST_INIT_MODE_test.Child_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_FAST_INIT_MODE_test.Child_MembersInjector
index 6040966..e744215 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_FAST_INIT_MODE_test.Child_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_subclassedGenericMembersInjectors_FAST_INIT_MODE_test.Child_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class Child_MembersInjector<T> implements MembersInjector<Child<T>> {
   private final Provider<T> xProvider;
@@ -45,6 +48,12 @@
     return new Child_MembersInjector<T>(xProvider, yProvider, a2Provider, aProvider, tProvider);
   }
 
+  public static <T> MembersInjector<Child<T>> create(javax.inject.Provider<T> xProvider,
+      javax.inject.Provider<A> yProvider, javax.inject.Provider<A2> a2Provider,
+      javax.inject.Provider<A> aProvider, javax.inject.Provider<T> tProvider) {
+    return new Child_MembersInjector<T>(Providers.asDaggerProvider(xProvider), Providers.asDaggerProvider(yProvider), Providers.asDaggerProvider(a2Provider), Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(tProvider));
+  }
+
   @Override
   public void injectMembers(Child<T> instance) {
     Parent_MembersInjector.injectX(instance, xProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_DEFAULT_MODE_test.B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_DEFAULT_MODE_test.B_MembersInjector
index 01f787b..175f9d6 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_DEFAULT_MODE_test.B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_DEFAULT_MODE_test.B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class B_MembersInjector implements MembersInjector<B> {
   private final Provider<String> sProvider;
@@ -31,6 +34,10 @@
     return new B_MembersInjector(sProvider);
   }
 
+  public static MembersInjector<B> create(javax.inject.Provider<String> sProvider) {
+    return new B_MembersInjector(Providers.asDaggerProvider(sProvider));
+  }
+
   @Override
   public void injectMembers(B instance) {
     injectS(instance, sProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_FAST_INIT_MODE_test.B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_FAST_INIT_MODE_test.B_MembersInjector
index 01f787b..175f9d6 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_FAST_INIT_MODE_test.B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_supertypeMembersInjection_FAST_INIT_MODE_test.B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class B_MembersInjector implements MembersInjector<B> {
   private final Provider<String> sProvider;
@@ -31,6 +34,10 @@
     return new B_MembersInjector(sProvider);
   }
 
+  public static MembersInjector<B> create(javax.inject.Provider<String> sProvider) {
+    return new B_MembersInjector(Providers.asDaggerProvider(sProvider));
+  }
+
   @Override
   public void injectMembers(B instance) {
     injectS(instance, sProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.A_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.A_MembersInjector
index f126251..dafed92 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.A_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.A_MembersInjector
@@ -2,9 +2,10 @@
 
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -17,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class A_MembersInjector implements MembersInjector<A> {
   private final Provider<String> valueBProvider;
@@ -30,6 +33,10 @@
     return new A_MembersInjector(valueBProvider);
   }
 
+  public static MembersInjector<A> create(javax.inject.Provider<String> valueBProvider) {
+    return new A_MembersInjector(Providers.asDaggerProvider(valueBProvider));
+  }
+
   @Override
   public void injectMembers(A instance) {
     B_MembersInjector.injectValueB(instance, valueBProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.B_MembersInjector
index 192947e..e9b2888 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_DEFAULT_MODE_test.B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class B_MembersInjector implements MembersInjector<B> {
   private final Provider<String> valueBProvider;
@@ -31,6 +34,10 @@
     return new B_MembersInjector(valueBProvider);
   }
 
+  public static MembersInjector<B> create(javax.inject.Provider<String> valueBProvider) {
+    return new B_MembersInjector(Providers.asDaggerProvider(valueBProvider));
+  }
+
   @Override
   public void injectMembers(B instance) {
     injectValueB(instance, valueBProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.A_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
index f126251..dafed92 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.A_MembersInjector
@@ -2,9 +2,10 @@
 
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -17,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class A_MembersInjector implements MembersInjector<A> {
   private final Provider<String> valueBProvider;
@@ -30,6 +33,10 @@
     return new A_MembersInjector(valueBProvider);
   }
 
+  public static MembersInjector<A> create(javax.inject.Provider<String> valueBProvider) {
+    return new A_MembersInjector(Providers.asDaggerProvider(valueBProvider));
+  }
+
   @Override
   public void injectMembers(A instance) {
     B_MembersInjector.injectValueB(instance, valueBProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.B_MembersInjector
index 192947e..e9b2888 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testConstructorInjectedFieldInjection_FAST_INIT_MODE_test.B_MembersInjector
@@ -3,9 +3,10 @@
 import dagger.MembersInjector;
 import dagger.internal.DaggerGenerated;
 import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @QualifierMetadata
 @DaggerGenerated
@@ -18,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class B_MembersInjector implements MembersInjector<B> {
   private final Provider<String> valueBProvider;
@@ -31,6 +34,10 @@
     return new B_MembersInjector(valueBProvider);
   }
 
+  public static MembersInjector<B> create(javax.inject.Provider<String> valueBProvider) {
+    return new B_MembersInjector(Providers.asDaggerProvider(valueBProvider));
+  }
+
   @Override
   public void injectMembers(B instance) {
     injectValueB(instance, valueBProvider.get());
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_DEFAULT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_DEFAULT_MODE_test.DaggerMyComponent
index c563a1a..12767ba 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_DEFAULT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_DEFAULT_MODE_test.DaggerMyComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_FAST_INIT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_FAST_INIT_MODE_test.DaggerMyComponent
index c563a1a..12767ba 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_FAST_INIT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingExistsInParentComponent_FAST_INIT_MODE_test.DaggerMyComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_DEFAULT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_DEFAULT_MODE_test.DaggerMyComponent
index 72140b3..ee72487 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_DEFAULT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_DEFAULT_MODE_test.DaggerMyComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_FAST_INIT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_FAST_INIT_MODE_test.DaggerMyComponent
index 72140b3..ee72487 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_FAST_INIT_MODE_test.DaggerMyComponent
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding_FAST_INIT_MODE_test.DaggerMyComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class DaggerMyComponent {
   private DaggerMyComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_DEFAULT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_DEFAULT_MODE_test.DaggerMyComponent
new file mode 100644
index 0000000..d47c1f2
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_DEFAULT_MODE_test.DaggerMyComponent
@@ -0,0 +1,58 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class DaggerMyComponent {
+  private DaggerMyComponent() {
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static MyComponent create() {
+    return new Builder().build();
+  }
+
+  public static final class Builder {
+    private Builder() {
+    }
+
+    public MyComponent build() {
+      return new MyComponentImpl();
+    }
+  }
+
+  private static final class MyComponentImpl implements MyComponent {
+    private final MyComponentImpl myComponentImpl = this;
+
+    private MyComponentImpl() {
+
+
+    }
+
+    @Override
+    public void inject(Foo foo) {
+    }
+
+    @Override
+    public Foo injectAndReturn(Foo foo) {
+      return foo;
+    }
+  }
+}
\ No newline at end of file
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_FAST_INIT_MODE_test.DaggerMyComponent b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_FAST_INIT_MODE_test.DaggerMyComponent
new file mode 100644
index 0000000..d47c1f2
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_testMembersInjectionBindingWithNoInjectionSites_FAST_INIT_MODE_test.DaggerMyComponent
@@ -0,0 +1,58 @@
+package test;
+
+import dagger.internal.DaggerGenerated;
+import javax.annotation.processing.Generated;
+
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class DaggerMyComponent {
+  private DaggerMyComponent() {
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static MyComponent create() {
+    return new Builder().build();
+  }
+
+  public static final class Builder {
+    private Builder() {
+    }
+
+    public MyComponent build() {
+      return new MyComponentImpl();
+    }
+  }
+
+  private static final class MyComponentImpl implements MyComponent {
+    private final MyComponentImpl myComponentImpl = this;
+
+    private MyComponentImpl() {
+
+
+    }
+
+    @Override
+    public void inject(Foo foo) {
+    }
+
+    @Override
+    public Foo injectAndReturn(Foo foo) {
+      return foo;
+    }
+  }
+}
\ No newline at end of file
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
new file mode 100644
index 0000000..ff27f6f
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_DEFAULT_MODE_test.FieldInjection_MembersInjector
@@ -0,0 +1,52 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
+  private final Provider<String> stringProvider;
+
+  public FieldInjection_MembersInjector(Provider<String> stringProvider) {
+    this.stringProvider = stringProvider;
+  }
+
+  public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(stringProvider);
+  }
+
+  public static MembersInjector<FieldInjection> create(
+      javax.inject.Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider));
+  }
+
+  @Override
+  public void injectMembers(FieldInjection instance) {
+    injectString(instance, stringProvider.get());
+  }
+
+  @InjectedFieldSignature("test.FieldInjection.string")
+  public static void injectString(Object instance, String string) {
+    ((FieldInjection) instance).string = string;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
new file mode 100644
index 0000000..ff27f6f
--- /dev/null
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_typeUseNullableFieldInjection_FAST_INIT_MODE_test.FieldInjection_MembersInjector
@@ -0,0 +1,52 @@
+package test;
+
+import dagger.MembersInjector;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.InjectedFieldSignature;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
+import dagger.internal.QualifierMetadata;
+import javax.annotation.processing.Generated;
+
+@QualifierMetadata
+@DaggerGenerated
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes",
+    "KotlinInternal",
+    "KotlinInternalInJava",
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
+})
+public final class FieldInjection_MembersInjector implements MembersInjector<FieldInjection> {
+  private final Provider<String> stringProvider;
+
+  public FieldInjection_MembersInjector(Provider<String> stringProvider) {
+    this.stringProvider = stringProvider;
+  }
+
+  public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(stringProvider);
+  }
+
+  public static MembersInjector<FieldInjection> create(
+      javax.inject.Provider<String> stringProvider) {
+    return new FieldInjection_MembersInjector(Providers.asDaggerProvider(stringProvider));
+  }
+
+  @Override
+  public void injectMembers(FieldInjection instance) {
+    injectString(instance, stringProvider.get());
+  }
+
+  @InjectedFieldSignature("test.FieldInjection.string")
+  public static void injectString(Object instance, String string) {
+    ((FieldInjection) instance).string = string;
+  }
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildIntegerModule_ProvideIntegerFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildIntegerModule_ProvideIntegerFactory
index 8b9a451..8489308 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildIntegerModule_ProvideIntegerFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildIntegerModule_ProvideIntegerFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ChildIntegerModule_ProvideIntegerFactory implements Factory<Integer> {
   private final ChildIntegerModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildNumberModule_ProvideNumberFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildNumberModule_ProvideNumberFactory
index d662cc6..84152fe 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildNumberModule_ProvideNumberFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ChildNumberModule_ProvideNumberFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ChildNumberModule_ProvideNumberFactory implements Factory<Number> {
   private final ChildNumberModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBElementFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBElementFactory
index d669e2a..69932bc 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBElementFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBElementFactory
@@ -3,10 +3,11 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParentModule_ProvideBElementFactory<A extends CharSequence, B, C extends Number & Comparable<C>> implements Factory<B> {
   private final ParentModule<A, B, C> module;
@@ -38,6 +41,11 @@
   }
 
   public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideBElementFactory<A, B, C> create(
+      ParentModule<A, B, C> module, javax.inject.Provider<B> bProvider) {
+    return new ParentModule_ProvideBElementFactory<A, B, C>(module, Providers.asDaggerProvider(bProvider));
+  }
+
+  public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideBElementFactory<A, B, C> create(
       ParentModule<A, B, C> module, Provider<B> bProvider) {
     return new ParentModule_ProvideBElementFactory<A, B, C>(module, bProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBEntryFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBEntryFactory
index 35052f4..2834c39 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBEntryFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideBEntryFactory
@@ -3,10 +3,11 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParentModule_ProvideBEntryFactory<A extends CharSequence, B, C extends Number & Comparable<C>> implements Factory<B> {
   private final ParentModule<A, B, C> module;
@@ -38,6 +41,11 @@
   }
 
   public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideBEntryFactory<A, B, C> create(
+      ParentModule<A, B, C> module, javax.inject.Provider<B> bProvider) {
+    return new ParentModule_ProvideBEntryFactory<A, B, C>(module, Providers.asDaggerProvider(bProvider));
+  }
+
+  public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideBEntryFactory<A, B, C> create(
       ParentModule<A, B, C> module, Provider<B> bProvider) {
     return new ParentModule_ProvideBEntryFactory<A, B, C>(module, bProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideListBFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideListBFactory
index a36bf26..72f9488 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideListBFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_genericSubclassedModule_test.ParentModule_ProvideListBFactory
@@ -3,11 +3,12 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParentModule_ProvideListBFactory<A extends CharSequence, B, C extends Number & Comparable<C>> implements Factory<List<B>> {
   private final ParentModule<A, B, C> module;
@@ -39,6 +42,11 @@
   }
 
   public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideListBFactory<A, B, C> create(
+      ParentModule<A, B, C> module, javax.inject.Provider<B> bProvider) {
+    return new ParentModule_ProvideListBFactory<A, B, C>(module, Providers.asDaggerProvider(bProvider));
+  }
+
+  public static <A extends CharSequence, B, C extends Number & Comparable<C>> ParentModule_ProvideListBFactory<A, B, C> create(
       ParentModule<A, B, C> module, Provider<B> bProvider) {
     return new ParentModule_ProvideListBFactory<A, B, C>(module, bProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_multipleProvidesMethods_test.TestModule_ProvideObjectsFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_multipleProvidesMethods_test.TestModule_ProvideObjectsFactory
index 63ae5bf..a5f7daa 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_multipleProvidesMethods_test.TestModule_ProvideObjectsFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_multipleProvidesMethods_test.TestModule_ProvideObjectsFactory
@@ -4,11 +4,12 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata({
@@ -25,7 +26,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideObjectsFactory implements Factory<List<Object>> {
   private final TestModule module;
@@ -50,6 +53,12 @@
   }
 
   public static TestModule_ProvideObjectsFactory create(TestModule module,
+      javax.inject.Provider<Object> aProvider, javax.inject.Provider<Object> bProvider,
+      javax.inject.Provider<MembersInjector<X>> xInjectorProvider) {
+    return new TestModule_ProvideObjectsFactory(module, Providers.asDaggerProvider(aProvider), Providers.asDaggerProvider(bProvider), Providers.asDaggerProvider(xInjectorProvider));
+  }
+
+  public static TestModule_ProvideObjectsFactory create(TestModule module,
       Provider<Object> aProvider, Provider<Object> bProvider,
       Provider<MembersInjector<X>> xInjectorProvider) {
     return new TestModule_ProvideObjectsFactory(module, aProvider, bProvider, xInjectorProvider);
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nonTypeUseNullableProvides_test.TestModule_ProvideStringFactory
similarity index 92%
rename from javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory
rename to javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nonTypeUseNullableProvides_test.TestModule_ProvideStringFactory
index 8e3b1cd..b2048a8 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nonTypeUseNullableProvides_test.TestModule_ProvideStringFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideStringFactory implements Factory<String> {
   private final TestModule module;
@@ -41,5 +43,4 @@
   public static String provideString(TestModule instance) {
     return instance.provideString();
   }
-}
-
+}
\ No newline at end of file
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideMapStringNumberFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideMapStringNumberFactory
index 9185ad3..e57b3a2 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideMapStringNumberFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideMapStringNumberFactory
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParameterizedModule_ProvideMapStringNumberFactory implements Factory<Map<String, Number>> {
   @Override
@@ -37,7 +39,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final ParameterizedModule_ProvideMapStringNumberFactory INSTANCE = new ParameterizedModule_ProvideMapStringNumberFactory();
+    static final ParameterizedModule_ProvideMapStringNumberFactory INSTANCE = new ParameterizedModule_ProvideMapStringNumberFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeFactory
index 29bea60..4c8f2ae 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParameterizedModule_ProvideNonGenericTypeFactory implements Factory<Object> {
   @Override
@@ -36,7 +38,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final ParameterizedModule_ProvideNonGenericTypeFactory INSTANCE = new ParameterizedModule_ProvideNonGenericTypeFactory();
+    static final ParameterizedModule_ProvideNonGenericTypeFactory INSTANCE = new ParameterizedModule_ProvideNonGenericTypeFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeWithDepsFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeWithDepsFactory
index 4f91376..f0b0873 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeWithDepsFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_parameterizedModuleWithStaticProvidesMethodOfGenericType_test.ParameterizedModule_ProvideNonGenericTypeWithDepsFactory
@@ -3,10 +3,11 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata
@@ -20,7 +21,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class ParameterizedModule_ProvideNonGenericTypeWithDepsFactory implements Factory<String> {
   private final Provider<Object> oProvider;
@@ -35,6 +38,11 @@
   }
 
   public static ParameterizedModule_ProvideNonGenericTypeWithDepsFactory create(
+      javax.inject.Provider<Object> oProvider) {
+    return new ParameterizedModule_ProvideNonGenericTypeWithDepsFactory(Providers.asDaggerProvider(oProvider));
+  }
+
+  public static ParameterizedModule_ProvideNonGenericTypeWithDepsFactory create(
       Provider<Object> oProvider) {
     return new ParameterizedModule_ProvideNonGenericTypeWithDepsFactory(oProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElementWildcard_test.TestModule_ProvideWildcardListFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElementWildcard_test.TestModule_ProvideWildcardListFactory
index 6fabfaa..491bafd 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElementWildcard_test.TestModule_ProvideWildcardListFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElementWildcard_test.TestModule_ProvideWildcardListFactory
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideWildcardListFactory implements Factory<List<List<?>>> {
   private final TestModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElement_test.TestModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElement_test.TestModule_ProvideStringFactory
index 6675a41..36dfacf 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElement_test.TestModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetElement_test.TestModule_ProvideStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideStringFactory implements Factory<String> {
   private final TestModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetValues_test.TestModule_ProvideStringsFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetValues_test.TestModule_ProvideStringsFactory
index 240620f..5f22922 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetValues_test.TestModule_ProvideStringsFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_providesSetValues_test.TestModule_ProvideStringsFactory
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {
   private final TestModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_CreateFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_CreateFactory
index 9250da8..a21af1c 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_CreateFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_CreateFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_CreateFactory implements Factory<Boolean> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_CreateFactory INSTANCE = new TestModule_CreateFactory();
+    static final TestModule_CreateFactory INSTANCE = new TestModule_CreateFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_GetFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_GetFactory
index 52eb228..244868a 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_GetFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_proxyMethodsConflictWithOtherFactoryMethods_test.TestModule_GetFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_GetFactory implements Factory<Integer> {
   @Override
@@ -35,7 +37,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final TestModule_GetFactory INSTANCE = new TestModule_GetFactory();
+    static final TestModule_GetFactory INSTANCE = new TestModule_GetFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_disableNullable_test.TestModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_disableNullable_test.TestModule_ProvideStringFactory
index 9755887..17fedfa 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_disableNullable_test.TestModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_disableNullable_test.TestModule_ProvideStringFactory
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideStringFactory implements Factory<String> {
   private final TestModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_test.TestModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_test.TestModule_ProvideStringFactory
index 6675a41..36dfacf 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_test.TestModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_singleProvidesMethodNoArgs_test.TestModule_ProvideStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProvideStringFactory implements Factory<String> {
   private final TestModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testQualifierMetadataOnProvides_test.MyModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testQualifierMetadataOnProvides_test.MyModule_ProvideStringFactory
index e62e7b9..a760296 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testQualifierMetadataOnProvides_test.MyModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testQualifierMetadataOnProvides_test.MyModule_ProvideStringFactory
@@ -3,10 +3,11 @@
 import dagger.internal.DaggerGenerated;
 import dagger.internal.Factory;
 import dagger.internal.Preconditions;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.internal.QualifierMetadata;
 import dagger.internal.ScopeMetadata;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @ScopeMetadata
 @QualifierMetadata({
@@ -23,7 +24,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MyModule_ProvideStringFactory implements Factory<String> {
   private final Provider<Integer> iProvider;
@@ -37,6 +40,10 @@
     return provideString(iProvider.get());
   }
 
+  public static MyModule_ProvideStringFactory create(javax.inject.Provider<Integer> iProvider) {
+    return new MyModule_ProvideStringFactory(Providers.asDaggerProvider(iProvider));
+  }
+
   public static MyModule_ProvideStringFactory create(Provider<Integer> iProvider) {
     return new MyModule_ProvideStringFactory(iProvider);
   }
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopeMetadataWithCustomScope_test.MyModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopeMetadataWithCustomScope_test.MyModule_ProvideStringFactory
index 8ec360d..689e523 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopeMetadataWithCustomScope_test.MyModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopeMetadataWithCustomScope_test.MyModule_ProvideStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MyModule_ProvideStringFactory implements Factory<String> {
   @Override
@@ -36,7 +38,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final MyModule_ProvideStringFactory INSTANCE = new MyModule_ProvideStringFactory();
+    static final MyModule_ProvideStringFactory INSTANCE = new MyModule_ProvideStringFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnNonStaticProvides_test.MyModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnNonStaticProvides_test.MyModule_ProvideStringFactory
index e5a04c5..2e42d1f 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnNonStaticProvides_test.MyModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnNonStaticProvides_test.MyModule_ProvideStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MyModule_ProvideStringFactory implements Factory<String> {
   private final MyModule module;
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnStaticProvides_test.MyModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnStaticProvides_test.MyModule_ProvideStringFactory
index b88b3e3..cf42878 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnStaticProvides_test.MyModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_testScopedMetadataOnStaticProvides_test.MyModule_ProvideStringFactory
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class MyModule_ProvideStringFactory implements Factory<String> {
   @Override
@@ -36,7 +38,7 @@
   }
 
   private static final class InstanceHolder {
-    private static final MyModule_ProvideStringFactory INSTANCE = new MyModule_ProvideStringFactory();
+    static final MyModule_ProvideStringFactory INSTANCE = new MyModule_ProvideStringFactory();
   }
 }
 
diff --git a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_typeUseNullableProvides_test.TestModule_ProvideStringFactory
similarity index 81%
copy from javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory
copy to javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_typeUseNullableProvides_test.TestModule_ProvideStringFactory
index 8e3b1cd..7440fb8 100644
--- a/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_nullableProvides_test.TestModule_ProvideStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ModuleFactoryGeneratorTest_typeUseNullableProvides_test.TestModule_ProvideStringFactory
@@ -18,9 +18,11 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
-public final class TestModule_ProvideStringFactory implements Factory<String> {
+public final class TestModule_ProvideStringFactory implements Factory<@Nullable String> {
   private final TestModule module;
 
   public TestModule_ProvideStringFactory(TestModule module) {
@@ -28,8 +30,7 @@
   }
 
   @Override
-  @Nullable
-  public String get() {
+  public @Nullable String get() {
     return provideString(module);
   }
 
@@ -37,9 +38,7 @@
     return new TestModule_ProvideStringFactory(module);
   }
 
-  @Nullable
-  public static String provideString(TestModule instance) {
+  public static @Nullable String provideString(TestModule instance) {
     return instance.provideString();
   }
 }
-
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index 37c1bb8..0000000
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,75 +0,0 @@
-package test;
-
-import com.google.common.base.Optional;
-import dagger.Lazy;
-import dagger.internal.DaggerGenerated;
-import dagger.internal.ProviderOfLazy;
-import javax.annotation.Generated;
-import javax.inject.Provider;
-import other.DefinitelyNot;
-import other.Maybe;
-import other.Maybe_MaybeModule_ProvideMaybeFactory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private TestComponentImpl() {
-
-
-    }
-
-    @Override
-    public Optional<Maybe> maybe() {
-      return Optional.of(Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe());
-    }
-
-    @Override
-    public Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {
-      return (Optional) Optional.of(ProviderOfLazy.create(Maybe_MaybeModule_ProvideMaybeFactory.create()));
-    }
-
-    @Override
-    public Optional<DefinitelyNot> definitelyNot() {
-      return Optional.<DefinitelyNot>absent();
-    }
-
-    @Override
-    public Optional<Provider<Lazy<DefinitelyNot>>> providerOfLazyOfDefinitelyNot() {
-      return (Optional) Optional.<Provider<Lazy<DefinitelyNot>>>absent();
-    }
-  }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_MODE_test.DaggerTestComponent
index 0884286..02c758a 100644
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index f1ab214..0000000
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,105 +0,0 @@
-package test;
-
-import com.google.common.base.Optional;
-import dagger.Lazy;
-import dagger.internal.DaggerGenerated;
-import dagger.internal.Provider;
-import dagger.internal.ProviderOfLazy;
-import javax.annotation.Generated;
-import other.DefinitelyNot;
-import other.Maybe;
-import other.Maybe_MaybeModule_ProvideMaybeFactory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private Provider<Maybe> provideMaybeProvider;
-
-    private TestComponentImpl() {
-
-      initialize();
-
-    }
-
-    @SuppressWarnings("unchecked")
-    private void initialize() {
-      this.provideMaybeProvider = new SwitchingProvider<Maybe>(testComponentImpl, 0);
-    }
-
-    @Override
-    public Optional<Maybe> maybe() {
-      return Optional.of(provideMaybeProvider.get());
-    }
-
-    @Override
-    public Optional<javax.inject.Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {
-      return (Optional) Optional.of(ProviderOfLazy.create(provideMaybeProvider));
-    }
-
-    @Override
-    public Optional<DefinitelyNot> definitelyNot() {
-      return Optional.<DefinitelyNot>absent();
-    }
-
-    @Override
-    public Optional<javax.inject.Provider<Lazy<DefinitelyNot>>> providerOfLazyOfDefinitelyNot() {
-      return (Optional) Optional.<javax.inject.Provider<Lazy<DefinitelyNot>>>absent();
-    }
-
-    private static final class SwitchingProvider<T> implements Provider<T> {
-      private final TestComponentImpl testComponentImpl;
-
-      private final int id;
-
-      SwitchingProvider(TestComponentImpl testComponentImpl, int id) {
-        this.testComponentImpl = testComponentImpl;
-        this.id = id;
-      }
-
-      @SuppressWarnings("unchecked")
-      @Override
-      public T get() {
-        switch (id) {
-          case 0: // other.Maybe 
-          return (T) Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe();
-
-          default: throw new AssertionError(id);
-        }
-      }
-    }
-  }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_MODE_test.DaggerTestComponent
index 83b8f81..c92f61f 100644
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_inlinedOptionalBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index 9d278cb..0000000
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,71 +0,0 @@
-package test;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.DaggerGenerated;
-import dagger.producers.internal.CancellationListener;
-import javax.annotation.Generated;
-import other.DefinitelyNot;
-import other.Maybe;
-import other.Maybe_MaybeModule_ProvideMaybeFactory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent, CancellationListener {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private TestComponentImpl() {
-
-
-    }
-
-    @Override
-    public ListenableFuture<Optional<Maybe>> maybe() {
-      return Futures.immediateFuture(Optional.of(Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe()));
-    }
-
-    @Override
-    public ListenableFuture<Optional<DefinitelyNot>> definitelyNot() {
-      return Futures.immediateFuture(Optional.<DefinitelyNot>absent());
-    }
-
-    @Override
-    public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {
-
-
-    }
-  }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_MODE_test.DaggerTestComponent
index e6e1d5a..3dc568f 100644
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_DEFAULT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
deleted file mode 100644
index 9d278cb..0000000
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_JAVA7_MODE_test.DaggerTestComponent
+++ /dev/null
@@ -1,71 +0,0 @@
-package test;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.DaggerGenerated;
-import dagger.producers.internal.CancellationListener;
-import javax.annotation.Generated;
-import other.DefinitelyNot;
-import other.Maybe;
-import other.Maybe_MaybeModule_ProvideMaybeFactory;
-
-@DaggerGenerated
-@Generated(
-    value = "dagger.internal.codegen.ComponentProcessor",
-    comments = "https://dagger.dev"
-)
-@SuppressWarnings({
-    "unchecked",
-    "rawtypes",
-    "KotlinInternal",
-    "KotlinInternalInJava",
-    "cast"
-})
-final class DaggerTestComponent {
-  private DaggerTestComponent() {
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static TestComponent create() {
-    return new Builder().build();
-  }
-
-  static final class Builder {
-    private Builder() {
-    }
-
-    public TestComponent build() {
-      return new TestComponentImpl();
-    }
-  }
-
-  private static final class TestComponentImpl implements TestComponent, CancellationListener {
-    private final TestComponentImpl testComponentImpl = this;
-
-    private TestComponentImpl() {
-
-
-    }
-
-    @Override
-    public ListenableFuture<Optional<Maybe>> maybe() {
-      return Futures.immediateFuture(Optional.of(Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe()));
-    }
-
-    @Override
-    public ListenableFuture<Optional<DefinitelyNot>> definitelyNot() {
-      return Futures.immediateFuture(Optional.<DefinitelyNot>absent());
-    }
-
-    @Override
-    public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {
-
-
-    }
-  }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_MODE_test.DaggerTestComponent
index e6e1d5a..3dc568f 100644
--- a/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/OptionalBindingRequestFulfillmentTest_requestForFuture_FAST_INIT_MODE_test.DaggerTestComponent
@@ -20,7 +20,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFutureWithProducerName_test.TestModule_ProduceStringFactory b/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFutureWithProducerName_test.TestModule_ProduceStringFactory
index 048cdc8..7b625c9 100644
--- a/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFutureWithProducerName_test.TestModule_ProduceStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFutureWithProducerName_test.TestModule_ProduceStringFactory
@@ -3,12 +3,13 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.producers.internal.AbstractProducesMethodProducer;
 import dagger.producers.monitoring.ProducerToken;
 import dagger.producers.monitoring.ProductionComponentMonitor;
 import java.util.concurrent.Executor;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @DaggerGenerated
 @Generated(
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProduceStringFactory extends AbstractProducesMethodProducer<Void, String> {
   private final TestModule module;
@@ -38,6 +41,12 @@
     return new TestModule_ProduceStringFactory(module, executorProvider, productionComponentMonitorProvider);
   }
 
+  public static TestModule_ProduceStringFactory create(TestModule module,
+      javax.inject.Provider<Executor> executorProvider,
+      javax.inject.Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {
+    return new TestModule_ProduceStringFactory(module, Providers.asDaggerProvider(executorProvider), Providers.asDaggerProvider(productionComponentMonitorProvider));
+  }
+
   @Override
   protected ListenableFuture<Void> collectDependencies() {
     return Futures.<Void>immediateFuture(null);
diff --git a/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFuture_test.TestModule_ProduceStringFactory b/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFuture_test.TestModule_ProduceStringFactory
index 248ceb1..3125538 100644
--- a/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFuture_test.TestModule_ProduceStringFactory
+++ b/javatests/dagger/internal/codegen/goldens/ProducerModuleFactoryGeneratorTest_singleProducesMethodNoArgsFuture_test.TestModule_ProduceStringFactory
@@ -3,12 +3,13 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import dagger.internal.DaggerGenerated;
+import dagger.internal.Provider;
+import dagger.internal.Providers;
 import dagger.producers.internal.AbstractProducesMethodProducer;
 import dagger.producers.monitoring.ProducerToken;
 import dagger.producers.monitoring.ProductionComponentMonitor;
 import java.util.concurrent.Executor;
 import javax.annotation.processing.Generated;
-import javax.inject.Provider;
 
 @DaggerGenerated
 @Generated(
@@ -21,7 +22,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 public final class TestModule_ProduceStringFactory extends AbstractProducesMethodProducer<Void, String> {
   private final TestModule module;
@@ -38,6 +41,12 @@
     return new TestModule_ProduceStringFactory(module, executorProvider, productionComponentMonitorProvider);
   }
 
+  public static TestModule_ProduceStringFactory create(TestModule module,
+      javax.inject.Provider<Executor> executorProvider,
+      javax.inject.Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {
+    return new TestModule_ProduceStringFactory(module, Providers.asDaggerProvider(executorProvider), Providers.asDaggerProvider(productionComponentMonitorProvider));
+  }
+
   @Override
   protected ListenableFuture<Void> collectDependencies() {
     return Futures.<Void>immediateFuture(null);
diff --git a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_DEFAULT_MODE_test.DaggerParent
index 3b72cd4..16c1916 100644
--- a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_DEFAULT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_FAST_INIT_MODE_test.DaggerParent
index ab89bab..60be601 100644
--- a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_productionScope_injectConstructor_FAST_INIT_MODE_test.DaggerParent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerTestClass_SimpleComponent b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerTestClass_SimpleComponent
index 6146004..e1b2656 100644
--- a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerTestClass_SimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_DEFAULT_MODE_test.DaggerTestClass_SimpleComponent
@@ -24,7 +24,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestClass_SimpleComponent {
   private DaggerTestClass_SimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerTestClass_SimpleComponent b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerTestClass_SimpleComponent
index c5df7dc..f7f665b 100644
--- a/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerTestClass_SimpleComponent
+++ b/javatests/dagger/internal/codegen/goldens/ProductionComponentProcessorTest_simpleComponent_FAST_INIT_MODE_test.DaggerTestClass_SimpleComponent
@@ -24,7 +24,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestClass_SimpleComponent {
   private DaggerTestClass_SimpleComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
index 988302c..eacd584 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
index 988302c..eacd584 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
@@ -19,7 +19,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
index f56f0e6..94ee40b 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
index f56f0e6..94ee40b 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
index e69fffe..8ffdd23 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
index e69fffe..8ffdd23 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerTestComponent
index 2ffdfd2..301a2ad 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerTestComponent
index 2ffdfd2..301a2ad 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
index 1d16978..043ea3f 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
index 1d16978..043ea3f 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_inaccessible_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
index a6836ce..ceaaa81 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
index a6836ce..ceaaa81 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_productionComponents_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
index e2ff2df..2f5fdb9 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
index e2ff2df..2f5fdb9 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_setBindings_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
index 9b03019..8f07d5b 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_DEFAULT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
index 9b03019..8f07d5b 100644
--- a/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
+++ b/javatests/dagger/internal/codegen/goldens/SetBindingRequestFulfillmentWithGuavaTest_subcomponentOmitsInheritedBindings_FAST_INIT_MODE_test.DaggerParent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParent {
   private DaggerParent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
index a2352f6..dc1cbbd 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
index a0c7080..0d73ecb 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=DEFAULT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
index a2352f6..dc1cbbd 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Builder_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
index a0c7080..0d73ecb 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentCreatorRequestFulfillmentTest_testInlinedSubcomponentCreators_componentMethod_compilerMode=FAST_INIT_MODE, creatorKind=dagger.Subcomponent.Factory_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_DEFAULT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_DEFAULT_MODE_test.DaggerParentComponent
index 3a24c10..be66b6a 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_DEFAULT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_DEFAULT_MODE_test.DaggerParentComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_FAST_INIT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_FAST_INIT_MODE_test.DaggerParentComponent
index 4cbe543..4f15c13 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_FAST_INIT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent_FAST_INIT_MODE_test.DaggerParentComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
@@ -113,9 +115,9 @@
     }
 
     @CanIgnoreReturnValue
-    private Dep2 injectDep2(Dep2 instance) {
-      Dep2_MembersInjector.injectDep2Method(instance);
-      return instance;
+    private Dep2 injectDep2(Dep2 instance2) {
+      Dep2_MembersInjector.injectDep2Method(instance2);
+      return instance2;
     }
 
     private static final class SwitchingProvider<T> implements Provider<T> {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_DEFAULT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_DEFAULT_MODE_test.DaggerParentComponent
index 245871b..8984fcd 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_DEFAULT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_DEFAULT_MODE_test.DaggerParentComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_FAST_INIT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_FAST_INIT_MODE_test.DaggerParentComponent
index 245871b..8984fcd 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_FAST_INIT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent_FAST_INIT_MODE_test.DaggerParentComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_DEFAULT_MODE_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_DEFAULT_MODE_test.DaggerC
index c866218..b07408c 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_DEFAULT_MODE_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_DEFAULT_MODE_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_FAST_INIT_MODE_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_FAST_INIT_MODE_test.DaggerC
index c866218..b07408c 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_FAST_INIT_MODE_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentBuilderNamesShouldNotConflict_FAST_INIT_MODE_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_DEFAULT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_DEFAULT_MODE_test.DaggerParentComponent
index a778a05..e104079 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_DEFAULT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_DEFAULT_MODE_test.DaggerParentComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_FAST_INIT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_FAST_INIT_MODE_test.DaggerParentComponent
index a778a05..e104079 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_FAST_INIT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary_FAST_INIT_MODE_test.DaggerParentComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_DEFAULT_MODE_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_DEFAULT_MODE_test.DaggerC
index e2c98e3..72e4ca3 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_DEFAULT_MODE_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_DEFAULT_MODE_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_FAST_INIT_MODE_test.DaggerC b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_FAST_INIT_MODE_test.DaggerC
index e2c98e3..72e4ca3 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_FAST_INIT_MODE_test.DaggerC
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentNamesShouldNotConflictWithParent_FAST_INIT_MODE_test.DaggerC
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerC {
   private DaggerC() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_DEFAULT_MODE_DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_DEFAULT_MODE_DaggerParentComponent
index 7b47466..248f63b 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_DEFAULT_MODE_DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_DEFAULT_MODE_DaggerParentComponent
@@ -11,7 +11,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_FAST_INIT_MODE_DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_FAST_INIT_MODE_DaggerParentComponent
index 7b47466..248f63b 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_FAST_INIT_MODE_DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguatedInRoot_FAST_INIT_MODE_DaggerParentComponent
@@ -11,7 +11,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_DEFAULT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_DEFAULT_MODE_test.DaggerParentComponent
index 6a9942d..80a1c20 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_DEFAULT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_DEFAULT_MODE_test.DaggerParentComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_FAST_INIT_MODE_test.DaggerParentComponent b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_FAST_INIT_MODE_test.DaggerParentComponent
index 6a9942d..80a1c20 100644
--- a/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_FAST_INIT_MODE_test.DaggerParentComponent
+++ b/javatests/dagger/internal/codegen/goldens/SubcomponentValidationTest_subcomponentSimpleNamesDisambiguated_FAST_INIT_MODE_test.DaggerParentComponent
@@ -13,7 +13,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerParentComponent {
   private DaggerParentComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_DEFAULT_MODE_test.DaggerTestComponent
index 0ac7a6d..63269bd 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_DEFAULT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_FAST_INIT_MODE_test.DaggerTestComponent
index 0ac7a6d..63269bd 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_emptyMultibindings_avoidSwitchProviders_FAST_INIT_MODE_test.DaggerTestComponent
@@ -18,7 +18,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_DEFAULT_MODE_test.DaggerTestComponent
index db768e1..b03b718 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_FAST_INIT_MODE_test.DaggerTestComponent
index db768e1..b03b718 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_memberInjectors_FAST_INIT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_DEFAULT_MODE_test.DaggerTestComponent
index c474dc4..6adde95 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_DEFAULT_MODE_test.DaggerTestComponent
@@ -17,7 +17,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   /**
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_FAST_INIT_MODE_test.DaggerTestComponent
index 54d032d..9998715 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_optionals_FAST_INIT_MODE_test.DaggerTestComponent
@@ -16,7 +16,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   /**
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_DEFAULT_MODE_test.DaggerTestComponent
index ab66d4e..9c4c841 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_DEFAULT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
index 0a7cdb2..18ccb9c 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_scopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
@@ -15,7 +15,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_DEFAULT_MODE_test.DaggerTestComponent
index ade9e53..48520b4 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_FAST_INIT_MODE_test.DaggerTestComponent
index e225c47..70d0364 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_switchingProviderTest_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
@@ -246,6 +248,9 @@
 
       initialize();
       initialize2();
+      initialize3();
+      initialize4();
+      initialize5();
 
     }
 
@@ -276,6 +281,10 @@
       this.binding22Provider = new SwitchingProvider<>(testComponentImpl, 22);
       this.binding23Provider = new SwitchingProvider<>(testComponentImpl, 23);
       this.binding24Provider = new SwitchingProvider<>(testComponentImpl, 24);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void initialize2() {
       this.binding25Provider = new SwitchingProvider<>(testComponentImpl, 25);
       this.binding26Provider = new SwitchingProvider<>(testComponentImpl, 26);
       this.binding27Provider = new SwitchingProvider<>(testComponentImpl, 27);
@@ -301,6 +310,10 @@
       this.binding47Provider = new SwitchingProvider<>(testComponentImpl, 47);
       this.binding48Provider = new SwitchingProvider<>(testComponentImpl, 48);
       this.binding49Provider = new SwitchingProvider<>(testComponentImpl, 49);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void initialize3() {
       this.binding50Provider = new SwitchingProvider<>(testComponentImpl, 50);
       this.binding51Provider = new SwitchingProvider<>(testComponentImpl, 51);
       this.binding52Provider = new SwitchingProvider<>(testComponentImpl, 52);
@@ -326,6 +339,10 @@
       this.binding72Provider = new SwitchingProvider<>(testComponentImpl, 72);
       this.binding73Provider = new SwitchingProvider<>(testComponentImpl, 73);
       this.binding74Provider = new SwitchingProvider<>(testComponentImpl, 74);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void initialize4() {
       this.binding75Provider = new SwitchingProvider<>(testComponentImpl, 75);
       this.binding76Provider = new SwitchingProvider<>(testComponentImpl, 76);
       this.binding77Provider = new SwitchingProvider<>(testComponentImpl, 77);
@@ -354,7 +371,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    private void initialize2() {
+    private void initialize5() {
       this.binding100Provider = new SwitchingProvider<>(testComponentImpl, 100);
     }
 
@@ -876,304 +893,304 @@
       @SuppressWarnings("unchecked")
       private T get0() {
         switch (id) {
-          case 0: // test.Binding0 
+          case 0: // test.Binding0
           return (T) new Binding0();
 
-          case 1: // test.Binding1 
+          case 1: // test.Binding1
           return (T) new Binding1();
 
-          case 2: // test.Binding2 
+          case 2: // test.Binding2
           return (T) new Binding2();
 
-          case 3: // test.Binding3 
+          case 3: // test.Binding3
           return (T) new Binding3();
 
-          case 4: // test.Binding4 
+          case 4: // test.Binding4
           return (T) new Binding4();
 
-          case 5: // test.Binding5 
+          case 5: // test.Binding5
           return (T) new Binding5();
 
-          case 6: // test.Binding6 
+          case 6: // test.Binding6
           return (T) new Binding6();
 
-          case 7: // test.Binding7 
+          case 7: // test.Binding7
           return (T) new Binding7();
 
-          case 8: // test.Binding8 
+          case 8: // test.Binding8
           return (T) new Binding8();
 
-          case 9: // test.Binding9 
+          case 9: // test.Binding9
           return (T) new Binding9();
 
-          case 10: // test.Binding10 
+          case 10: // test.Binding10
           return (T) new Binding10();
 
-          case 11: // test.Binding11 
+          case 11: // test.Binding11
           return (T) new Binding11();
 
-          case 12: // test.Binding12 
+          case 12: // test.Binding12
           return (T) new Binding12();
 
-          case 13: // test.Binding13 
+          case 13: // test.Binding13
           return (T) new Binding13();
 
-          case 14: // test.Binding14 
+          case 14: // test.Binding14
           return (T) new Binding14();
 
-          case 15: // test.Binding15 
+          case 15: // test.Binding15
           return (T) new Binding15();
 
-          case 16: // test.Binding16 
+          case 16: // test.Binding16
           return (T) new Binding16();
 
-          case 17: // test.Binding17 
+          case 17: // test.Binding17
           return (T) new Binding17();
 
-          case 18: // test.Binding18 
+          case 18: // test.Binding18
           return (T) new Binding18();
 
-          case 19: // test.Binding19 
+          case 19: // test.Binding19
           return (T) new Binding19();
 
-          case 20: // test.Binding20 
+          case 20: // test.Binding20
           return (T) new Binding20();
 
-          case 21: // test.Binding21 
+          case 21: // test.Binding21
           return (T) new Binding21();
 
-          case 22: // test.Binding22 
+          case 22: // test.Binding22
           return (T) new Binding22();
 
-          case 23: // test.Binding23 
+          case 23: // test.Binding23
           return (T) new Binding23();
 
-          case 24: // test.Binding24 
+          case 24: // test.Binding24
           return (T) new Binding24();
 
-          case 25: // test.Binding25 
+          case 25: // test.Binding25
           return (T) new Binding25();
 
-          case 26: // test.Binding26 
+          case 26: // test.Binding26
           return (T) new Binding26();
 
-          case 27: // test.Binding27 
+          case 27: // test.Binding27
           return (T) new Binding27();
 
-          case 28: // test.Binding28 
+          case 28: // test.Binding28
           return (T) new Binding28();
 
-          case 29: // test.Binding29 
+          case 29: // test.Binding29
           return (T) new Binding29();
 
-          case 30: // test.Binding30 
+          case 30: // test.Binding30
           return (T) new Binding30();
 
-          case 31: // test.Binding31 
+          case 31: // test.Binding31
           return (T) new Binding31();
 
-          case 32: // test.Binding32 
+          case 32: // test.Binding32
           return (T) new Binding32();
 
-          case 33: // test.Binding33 
+          case 33: // test.Binding33
           return (T) new Binding33();
 
-          case 34: // test.Binding34 
+          case 34: // test.Binding34
           return (T) new Binding34();
 
-          case 35: // test.Binding35 
+          case 35: // test.Binding35
           return (T) new Binding35();
 
-          case 36: // test.Binding36 
+          case 36: // test.Binding36
           return (T) new Binding36();
 
-          case 37: // test.Binding37 
+          case 37: // test.Binding37
           return (T) new Binding37();
 
-          case 38: // test.Binding38 
+          case 38: // test.Binding38
           return (T) new Binding38();
 
-          case 39: // test.Binding39 
+          case 39: // test.Binding39
           return (T) new Binding39();
 
-          case 40: // test.Binding40 
+          case 40: // test.Binding40
           return (T) new Binding40();
 
-          case 41: // test.Binding41 
+          case 41: // test.Binding41
           return (T) new Binding41();
 
-          case 42: // test.Binding42 
+          case 42: // test.Binding42
           return (T) new Binding42();
 
-          case 43: // test.Binding43 
+          case 43: // test.Binding43
           return (T) new Binding43();
 
-          case 44: // test.Binding44 
+          case 44: // test.Binding44
           return (T) new Binding44();
 
-          case 45: // test.Binding45 
+          case 45: // test.Binding45
           return (T) new Binding45();
 
-          case 46: // test.Binding46 
+          case 46: // test.Binding46
           return (T) new Binding46();
 
-          case 47: // test.Binding47 
+          case 47: // test.Binding47
           return (T) new Binding47();
 
-          case 48: // test.Binding48 
+          case 48: // test.Binding48
           return (T) new Binding48();
 
-          case 49: // test.Binding49 
+          case 49: // test.Binding49
           return (T) new Binding49();
 
-          case 50: // test.Binding50 
+          case 50: // test.Binding50
           return (T) new Binding50();
 
-          case 51: // test.Binding51 
+          case 51: // test.Binding51
           return (T) new Binding51();
 
-          case 52: // test.Binding52 
+          case 52: // test.Binding52
           return (T) new Binding52();
 
-          case 53: // test.Binding53 
+          case 53: // test.Binding53
           return (T) new Binding53();
 
-          case 54: // test.Binding54 
+          case 54: // test.Binding54
           return (T) new Binding54();
 
-          case 55: // test.Binding55 
+          case 55: // test.Binding55
           return (T) new Binding55();
 
-          case 56: // test.Binding56 
+          case 56: // test.Binding56
           return (T) new Binding56();
 
-          case 57: // test.Binding57 
+          case 57: // test.Binding57
           return (T) new Binding57();
 
-          case 58: // test.Binding58 
+          case 58: // test.Binding58
           return (T) new Binding58();
 
-          case 59: // test.Binding59 
+          case 59: // test.Binding59
           return (T) new Binding59();
 
-          case 60: // test.Binding60 
+          case 60: // test.Binding60
           return (T) new Binding60();
 
-          case 61: // test.Binding61 
+          case 61: // test.Binding61
           return (T) new Binding61();
 
-          case 62: // test.Binding62 
+          case 62: // test.Binding62
           return (T) new Binding62();
 
-          case 63: // test.Binding63 
+          case 63: // test.Binding63
           return (T) new Binding63();
 
-          case 64: // test.Binding64 
+          case 64: // test.Binding64
           return (T) new Binding64();
 
-          case 65: // test.Binding65 
+          case 65: // test.Binding65
           return (T) new Binding65();
 
-          case 66: // test.Binding66 
+          case 66: // test.Binding66
           return (T) new Binding66();
 
-          case 67: // test.Binding67 
+          case 67: // test.Binding67
           return (T) new Binding67();
 
-          case 68: // test.Binding68 
+          case 68: // test.Binding68
           return (T) new Binding68();
 
-          case 69: // test.Binding69 
+          case 69: // test.Binding69
           return (T) new Binding69();
 
-          case 70: // test.Binding70 
+          case 70: // test.Binding70
           return (T) new Binding70();
 
-          case 71: // test.Binding71 
+          case 71: // test.Binding71
           return (T) new Binding71();
 
-          case 72: // test.Binding72 
+          case 72: // test.Binding72
           return (T) new Binding72();
 
-          case 73: // test.Binding73 
+          case 73: // test.Binding73
           return (T) new Binding73();
 
-          case 74: // test.Binding74 
+          case 74: // test.Binding74
           return (T) new Binding74();
 
-          case 75: // test.Binding75 
+          case 75: // test.Binding75
           return (T) new Binding75();
 
-          case 76: // test.Binding76 
+          case 76: // test.Binding76
           return (T) new Binding76();
 
-          case 77: // test.Binding77 
+          case 77: // test.Binding77
           return (T) new Binding77();
 
-          case 78: // test.Binding78 
+          case 78: // test.Binding78
           return (T) new Binding78();
 
-          case 79: // test.Binding79 
+          case 79: // test.Binding79
           return (T) new Binding79();
 
-          case 80: // test.Binding80 
+          case 80: // test.Binding80
           return (T) new Binding80();
 
-          case 81: // test.Binding81 
+          case 81: // test.Binding81
           return (T) new Binding81();
 
-          case 82: // test.Binding82 
+          case 82: // test.Binding82
           return (T) new Binding82();
 
-          case 83: // test.Binding83 
+          case 83: // test.Binding83
           return (T) new Binding83();
 
-          case 84: // test.Binding84 
+          case 84: // test.Binding84
           return (T) new Binding84();
 
-          case 85: // test.Binding85 
+          case 85: // test.Binding85
           return (T) new Binding85();
 
-          case 86: // test.Binding86 
+          case 86: // test.Binding86
           return (T) new Binding86();
 
-          case 87: // test.Binding87 
+          case 87: // test.Binding87
           return (T) new Binding87();
 
-          case 88: // test.Binding88 
+          case 88: // test.Binding88
           return (T) new Binding88();
 
-          case 89: // test.Binding89 
+          case 89: // test.Binding89
           return (T) new Binding89();
 
-          case 90: // test.Binding90 
+          case 90: // test.Binding90
           return (T) new Binding90();
 
-          case 91: // test.Binding91 
+          case 91: // test.Binding91
           return (T) new Binding91();
 
-          case 92: // test.Binding92 
+          case 92: // test.Binding92
           return (T) new Binding92();
 
-          case 93: // test.Binding93 
+          case 93: // test.Binding93
           return (T) new Binding93();
 
-          case 94: // test.Binding94 
+          case 94: // test.Binding94
           return (T) new Binding94();
 
-          case 95: // test.Binding95 
+          case 95: // test.Binding95
           return (T) new Binding95();
 
-          case 96: // test.Binding96 
+          case 96: // test.Binding96
           return (T) new Binding96();
 
-          case 97: // test.Binding97 
+          case 97: // test.Binding97
           return (T) new Binding97();
 
-          case 98: // test.Binding98 
+          case 98: // test.Binding98
           return (T) new Binding98();
 
-          case 99: // test.Binding99 
+          case 99: // test.Binding99
           return (T) new Binding99();
 
           default: throw new AssertionError(id);
@@ -1183,7 +1200,7 @@
       @SuppressWarnings("unchecked")
       private T get1() {
         switch (id) {
-          case 100: // test.Binding100 
+          case 100: // test.Binding100
           return (T) new Binding100();
 
           default: throw new AssertionError(id);
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_DEFAULT_MODE_test.DaggerTestComponent
index b2933ae..8566133 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_DEFAULT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
index eef5afc..4980ee3 100644
--- a/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/SwitchingProviderTest_unscopedBinds_FAST_INIT_MODE_test.DaggerTestComponent
@@ -14,7 +14,9 @@
     "rawtypes",
     "KotlinInternal",
     "KotlinInternalInJava",
-    "cast"
+    "cast",
+    "deprecation",
+    "nullness:initialization.field.uninitialized"
 })
 final class DaggerTestComponent {
   private DaggerTestComponent() {
diff --git a/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java b/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
index 20a57f1..9cf99cf 100644
--- a/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
@@ -39,58 +39,60 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      return new MyComponentImpl();",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private MyComponentImpl() {",
-                        "",
-                        "",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      return new MyComponentImpl();",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private MyComponentImpl() {",
+                      "",
+                      "",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 
   @Test
@@ -143,63 +145,65 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      return new MyComponentImpl();",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private MyComponentImpl() {",
-                        "",
-                        "",
-                        "    }",
-                        "",
-                        "    @Override",
-                        "    public Foo foo() {",
-                        "      return new Foo(new Bar());",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      return new MyComponentImpl();",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private MyComponentImpl() {",
+                      "",
+                      "",
+                      "    }",
+                      "",
+                      "    @Override",
+                      "    public Foo foo() {",
+                      "      return new Foo(new Bar());",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 
   @Test
@@ -225,73 +229,75 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import dagger.internal.Provider;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      return new MyComponentImpl();",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private Provider<Foo> fooProvider;",
-                        "",
-                        "    private MyComponentImpl() {",
-                        "",
-                        "      initialize();",
-                        "",
-                        "    }",
-                        "",
-                        "    @SuppressWarnings(\"unchecked\")",
-                        "    private void initialize() {",
-                        "      this.fooProvider = "
-                            + "Foo_Factory.create(Bar_Factory.create(), Bar_Factory.create());",
-                        "    }",
-                        "",
-                        "    @Override",
-                        "    public javax.inject.Provider<Foo> foo() {",
-                        "      return fooProvider;",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import dagger.internal.Provider;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      return new MyComponentImpl();",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private Provider<Foo> fooProvider;",
+                      "",
+                      "    private MyComponentImpl() {",
+                      "",
+                      "      initialize();",
+                      "",
+                      "    }",
+                      "",
+                      "    @SuppressWarnings(\"unchecked\")",
+                      "    private void initialize() {",
+                      "      this.fooProvider = "
+                          + "Foo_Factory.create(Bar_Factory.create(), Bar_Factory.create());",
+                      "    }",
+                      "",
+                      "    @Override",
+                      "    public javax.inject.Provider<Foo> foo() {",
+                      "      return fooProvider;",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 
   @Test
@@ -326,77 +332,79 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import dagger.internal.Preconditions;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private MyModule myModule;",
-                        "",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public Builder myModule(MyModule myModule) {",
-                        "      this.myModule = Preconditions.checkNotNull(myModule);",
-                        "      return this;",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      if (myModule == null) {",
-                        "        this.myModule = new MyModule();",
-                        "      }",
-                        "      return new MyComponentImpl(myModule);",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyModule myModule;",
-                        "",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private MyComponentImpl(MyModule myModuleParam) {",
-                        "      this.myModule = myModuleParam;",
-                        "",
-                        "    }",
-                        "",
-                        "    @Override",
-                        "    public Foo foo() {",
-                        "      return MyModule_ProvideFooFactory.provideFoo("
-                            + "myModule, MyModule_ProvideBarFactory.provideBar(myModule));",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import dagger.internal.Preconditions;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private MyModule myModule;",
+                      "",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public Builder myModule(MyModule myModule) {",
+                      "      this.myModule = Preconditions.checkNotNull(myModule);",
+                      "      return this;",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      if (myModule == null) {",
+                      "        this.myModule = new MyModule();",
+                      "      }",
+                      "      return new MyComponentImpl(myModule);",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyModule myModule;",
+                      "",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private MyComponentImpl(MyModule myModuleParam) {",
+                      "      this.myModule = myModuleParam;",
+                      "",
+                      "    }",
+                      "",
+                      "    @Override",
+                      "    public Foo foo() {",
+                      "      return MyModule_ProvideFooFactory.provideFoo("
+                          + "myModule, MyModule_ProvideBarFactory.provideBar(myModule));",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 
   @Test
@@ -432,84 +440,86 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import dagger.internal.Preconditions;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private MyModule myModule;",
-                        "",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public Builder myModule(MyModule myModule) {",
-                        "      this.myModule = Preconditions.checkNotNull(myModule);",
-                        "      return this;",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      if (myModule == null) {",
-                        "        this.myModule = new MyModule();",
-                        "      }",
-                        "      return new MyComponentImpl(myModule);",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyModule myModule;",
-                        "",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private MyComponentImpl(MyModule myModuleParam) {",
-                        "      this.myModule = myModuleParam;",
-                        "",
-                        "    }",
-                        "",
-                        "    @Override",
-                        "    public void injectFoo(Foo foo) {",
-                        "      injectFoo2(foo);",
-                        "    }",
-                        "",
-                        "    @CanIgnoreReturnValue",
-                        "    private Foo injectFoo2(Foo instance) {",
-                        "      Foo_MembersInjector.injectBar("
-                            + "instance, MyModule_ProvideBarFactory.provideBar(myModule));",
-                        "      return instance;",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import dagger.internal.Preconditions;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private MyModule myModule;",
+                      "",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public Builder myModule(MyModule myModule) {",
+                      "      this.myModule = Preconditions.checkNotNull(myModule);",
+                      "      return this;",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      if (myModule == null) {",
+                      "        this.myModule = new MyModule();",
+                      "      }",
+                      "      return new MyComponentImpl(myModule);",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyModule myModule;",
+                      "",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private MyComponentImpl(MyModule myModuleParam) {",
+                      "      this.myModule = myModuleParam;",
+                      "",
+                      "    }",
+                      "",
+                      "    @Override",
+                      "    public void injectFoo(Foo foo) {",
+                      "      injectFoo2(foo);",
+                      "    }",
+                      "",
+                      "    @CanIgnoreReturnValue",
+                      "    private Foo injectFoo2(Foo instance) {",
+                      "      Foo_MembersInjector.injectBar("
+                          + "instance, MyModule_ProvideBarFactory.provideBar(myModule));",
+                      "      return instance;",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 
   @Test
@@ -545,83 +555,85 @@
     CompilerTests.daggerCompiler(componentSrc)
         .compile(
             subject -> {
-                subject.hasErrorCount(0);
-                subject.generatedSource(
-                    CompilerTests.javaSource(
-                        "test/DaggerMyComponent",
-                        "package test;",
-                        "",
-                        "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
-                        "import dagger.internal.DaggerGenerated;",
-                        "import dagger.internal.Preconditions;",
-                        "import javax.annotation.processing.Generated;",
-                        "",
-                        "@DaggerGenerated",
-                        "@Generated(",
-                        "    value = \"dagger.internal.codegen.ComponentProcessor\",",
-                        "    comments = \"https://dagger.dev\"",
-                        ")",
-                        "@SuppressWarnings({",
-                        "    \"unchecked\",",
-                        "    \"rawtypes\",",
-                        "    \"KotlinInternal\",",
-                        "    \"KotlinInternalInJava\",",
-                        "    \"cast\"",
-                        "})",
-                        "public final class DaggerMyComponent {",
-                        "  private DaggerMyComponent() {",
-                        "  }",
-                        "",
-                        "  public static Builder builder() {",
-                        "    return new Builder();",
-                        "  }",
-                        "",
-                        "  public static MyComponent create() {",
-                        "    return new Builder().build();",
-                        "  }",
-                        "",
-                        "  public static final class Builder {",
-                        "    private MyModule myModule;",
-                        "",
-                        "    private Builder() {",
-                        "    }",
-                        "",
-                        "    public Builder myModule(MyModule myModule) {",
-                        "      this.myModule = Preconditions.checkNotNull(myModule);",
-                        "      return this;",
-                        "    }",
-                        "",
-                        "    public MyComponent build() {",
-                        "      if (myModule == null) {",
-                        "        this.myModule = new MyModule();",
-                        "      }",
-                        "      return new MyComponentImpl(myModule);",
-                        "    }",
-                        "  }",
-                        "",
-                        "  private static final class MyComponentImpl implements MyComponent {",
-                        "    private final MyModule myModule;",
-                        "",
-                        "    private final MyComponentImpl myComponentImpl = this;",
-                        "",
-                        "    private MyComponentImpl(MyModule myModuleParam) {",
-                        "      this.myModule = myModuleParam;",
-                        "",
-                        "    }",
-                        "",
-                        "    @Override",
-                        "    public Foo foo() {",
-                        "      return injectFoo(Foo_Factory.newInstance());",
-                        "    }",
-                        "",
-                        "    @CanIgnoreReturnValue",
-                        "    private Foo injectFoo(Foo instance) {",
-                        "      Foo_MembersInjector.injectBar("
-                            + "instance, MyModule_ProvideBarFactory.provideBar(myModule));",
-                        "      return instance;",
-                        "    }",
-                        "  }",
-                        "}"));
-              });
+              subject.hasErrorCount(0);
+              subject.generatedSource(
+                  CompilerTests.javaSource(
+                      "test/DaggerMyComponent",
+                      "package test;",
+                      "",
+                      "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
+                      "import dagger.internal.DaggerGenerated;",
+                      "import dagger.internal.Preconditions;",
+                      "import javax.annotation.processing.Generated;",
+                      "",
+                      "@DaggerGenerated",
+                      "@Generated(",
+                      "    value = \"dagger.internal.codegen.ComponentProcessor\",",
+                      "    comments = \"https://dagger.dev\"",
+                      ")",
+                      "@SuppressWarnings({",
+                      "    \"unchecked\",",
+                      "    \"rawtypes\",",
+                      "    \"KotlinInternal\",",
+                      "    \"KotlinInternalInJava\",",
+                      "    \"cast\",",
+                      "    \"deprecation\",",
+                      "    \"nullness:initialization.field.uninitialized\"",
+                      "})",
+                      "public final class DaggerMyComponent {",
+                      "  private DaggerMyComponent() {",
+                      "  }",
+                      "",
+                      "  public static Builder builder() {",
+                      "    return new Builder();",
+                      "  }",
+                      "",
+                      "  public static MyComponent create() {",
+                      "    return new Builder().build();",
+                      "  }",
+                      "",
+                      "  public static final class Builder {",
+                      "    private MyModule myModule;",
+                      "",
+                      "    private Builder() {",
+                      "    }",
+                      "",
+                      "    public Builder myModule(MyModule myModule) {",
+                      "      this.myModule = Preconditions.checkNotNull(myModule);",
+                      "      return this;",
+                      "    }",
+                      "",
+                      "    public MyComponent build() {",
+                      "      if (myModule == null) {",
+                      "        this.myModule = new MyModule();",
+                      "      }",
+                      "      return new MyComponentImpl(myModule);",
+                      "    }",
+                      "  }",
+                      "",
+                      "  private static final class MyComponentImpl implements MyComponent {",
+                      "    private final MyModule myModule;",
+                      "",
+                      "    private final MyComponentImpl myComponentImpl = this;",
+                      "",
+                      "    private MyComponentImpl(MyModule myModuleParam) {",
+                      "      this.myModule = myModuleParam;",
+                      "",
+                      "    }",
+                      "",
+                      "    @Override",
+                      "    public Foo foo() {",
+                      "      return injectFoo(Foo_Factory.newInstance());",
+                      "    }",
+                      "",
+                      "    @CanIgnoreReturnValue",
+                      "    private Foo injectFoo(Foo instance) {",
+                      "      Foo_MembersInjector.injectBar("
+                          + "instance, MyModule_ProvideBarFactory.provideBar(myModule));",
+                      "      return instance;",
+                      "    }",
+                      "  }",
+                      "}"));
+            });
   }
 }
diff --git a/javatests/dagger/lint/BUILD b/javatests/dagger/lint/BUILD
index 4252cca..21e1331 100644
--- a/javatests/dagger/lint/BUILD
+++ b/javatests/dagger/lint/BUILD
@@ -15,7 +15,7 @@
 # Description:
 #   Tests for the Dagger Lint Rules
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_test")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test")
 
 package(default_visibility = ["//:src"])
 
diff --git a/javatests/dagger/spi/BUILD b/javatests/dagger/spi/BUILD
index ef1dca0..c69c00f 100644
--- a/javatests/dagger/spi/BUILD
+++ b/javatests/dagger/spi/BUILD
@@ -15,12 +15,12 @@
 # Description:
 #   Tests for the Dagger SPI
 
-load("//:test_defs.bzl", "GenJavaTests")
 load(
     "//:build_defs.bzl",
     "DOCLINT_HTML_AND_SYNTAX",
     "DOCLINT_REFERENCES",
 )
+load("//:test_defs.bzl", "GenJavaTests")
 
 package(default_visibility = ["//:src"])
 
diff --git a/javatests/dagger/spi/SpiPluginTest.java b/javatests/dagger/spi/SpiPluginTest.java
index 3d8e586..d011d65 100644
--- a/javatests/dagger/spi/SpiPluginTest.java
+++ b/javatests/dagger/spi/SpiPluginTest.java
@@ -101,7 +101,7 @@
             message(
                 "[FailingPlugin] Bad Binding: @Inject test.Foo()",
                 "    test.Foo is requested at",
-                "        test.TestComponent.foo()"))
+                "        [test.TestComponent] test.TestComponent.foo()"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
   }
@@ -189,7 +189,7 @@
             message(
                 "[FailingPlugin] Bad Dependency: test.TestComponent.entryPoint() (entry point)",
                 "    test.EntryPoint is requested at",
-                "        test.TestComponent.entryPoint()"))
+                "        [test.TestComponent] test.TestComponent.entryPoint()"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
     assertThat(compilationFactory.compilationWithErrorOnDependency("dup1"))
@@ -197,9 +197,9 @@
             message(
                 "[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup1, …)",
                 "    test.Duplicated is injected at",
-                "        test.EntryPoint(…, dup1, …)",
+                "        [test.TestComponent] test.EntryPoint(…, dup1, …)",
                 "    test.EntryPoint is requested at",
-                "        test.TestComponent.entryPoint()"))
+                "        [test.TestComponent] test.TestComponent.entryPoint()"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
     assertThat(compilationFactory.compilationWithErrorOnDependency("dup2"))
@@ -207,9 +207,9 @@
             message(
                 "[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup2)",
                 "    test.Duplicated is injected at",
-                "        test.EntryPoint(…, dup2)",
+                "        [test.TestComponent] test.EntryPoint(…, dup2)",
                 "    test.EntryPoint is requested at",
-                "        test.TestComponent.entryPoint()"))
+                "        [test.TestComponent] test.TestComponent.entryPoint()"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
 
@@ -220,11 +220,11 @@
             message(
                 "[FailingPlugin] Bad Dependency: test.Foo(inFooDep)",
                 "    test.Duplicated is injected at",
-                "        test.Foo(inFooDep)",
+                "        [test.TestComponent] test.Foo(inFooDep)",
                 "    test.Foo is injected at",
-                "        test.EntryPoint(foo, …)",
+                "        [test.TestComponent] test.EntryPoint(foo, …)",
                 "    test.EntryPoint is requested at",
-                "        test.TestComponent.entryPoint()",
+                "        [test.TestComponent] test.TestComponent.entryPoint()",
                 "The following other entry points also depend on it:",
                 "    test.TestComponent.chain()"))
         .inFile(component)
@@ -284,7 +284,7 @@
                 "[FailingPlugin] Bad Dependency: "
                     + "test.TestSubcomponent.childEntryPoint() (entry point)",
                 "    test.EntryPoint is requested at",
-                "        test.TestSubcomponent.childEntryPoint()"
+                "        [test.TestSubcomponent] test.TestSubcomponent.childEntryPoint()"
                     + " [test.TestComponent → test.TestSubcomponent]"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
@@ -297,9 +297,9 @@
             message(
                 "[FailingPlugin] Bad Dependency: test.EntryPoint(foo)",
                 "    test.Foo is injected at",
-                "        test.EntryPoint(foo)",
+                "        [test.TestSubcomponent] test.EntryPoint(foo)",
                 "    test.EntryPoint is requested at",
-                "        test.TestSubcomponent.childEntryPoint() "
+                "        [test.TestSubcomponent] test.TestSubcomponent.childEntryPoint() "
                     + "[test.TestComponent → test.TestSubcomponent]"))
         .inFile(component)
         .onLineContaining("interface TestComponent");
@@ -470,13 +470,13 @@
             message(
                 "[FailingPlugin] Bad Binding: @Inject test.ExposedOnSubcomponent()",
                 "    test.ExposedOnSubcomponent is injected at",
-                "        test.Chain3(exposedOnSubcomponent)",
+                "        [test.TestComponent] test.Chain3(exposedOnSubcomponent)",
                 "    test.Chain3 is injected at",
-                "        test.Chain2(chain)",
+                "        [test.TestComponent] test.Chain2(chain)",
                 "    test.Chain2 is injected at",
-                "        test.Chain1(chain)",
+                "        [test.TestComponent] test.Chain1(chain)",
                 "    test.Chain1 is requested at",
-                "        test.TestComponent.chain()",
+                "        [test.TestComponent] test.TestComponent.chain()",
                 "The following other entry points also depend on it:",
                 "    test.TestSubcomponent.exposedOnSubcomponent() "
                     + "[test.TestComponent → test.TestSubcomponent]"))
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..c9bbf35
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,23 @@
+pluginManagement {
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.name = "dagger-parent"
+
+fun includeProject(name: String, path: String) {
+    include(name)
+    project(name).projectDir = File(path)
+}
+
+includeProject(":dagger", "gradle-projects/dagger-runtime")
diff --git a/test_defs.bzl b/test_defs.bzl
index 3b13626..ea8fbf5 100644
--- a/test_defs.bzl
+++ b/test_defs.bzl
@@ -17,7 +17,7 @@
 load("@rules_java//java:defs.bzl", "java_library", "java_test")
 load("//:build_defs.bzl", "JAVA_RELEASE_MIN")
 load(
-    "@io_bazel_rules_kotlin//kotlin:kotlin.bzl",
+    "@io_bazel_rules_kotlin//kotlin:jvm.bzl",
     "kt_jvm_library",
     "kt_jvm_test",
 )
@@ -27,7 +27,6 @@
 _NON_FUNCTIONAL_BUILD_VARIANTS = {None: []}
 _FUNCTIONAL_BUILD_VARIANTS = {
     None: [],  # The default build variant (no javacopts).
-    "ExtendsComponent": ["-Adagger.generatedClassExtendsComponent=enabled"],
     "Shards": ["-Adagger.keysPerComponentShard=2"],
     "FastInit": ["-Adagger.fastInit=enabled"],
     "FastInit_Shards": ["-Adagger.fastInit=enabled", "-Adagger.keysPerComponentShard=2"],
@@ -208,7 +207,9 @@
 
     build_variants = _FUNCTIONAL_BUILD_VARIANTS if functional else _NON_FUNCTIONAL_BUILD_VARIANTS
     for (variant_name, variant_javacopts) in build_variants.items():
+        merged_javacopts = javacopts + variant_javacopts
         for is_ksp in (True, False):
+            merged_plugins = plugins
             if variant_name:
                 suffix = "_" + variant_name
                 tags = [variant_name]
@@ -233,8 +234,8 @@
                     srcs = supporting_files,
                     tags = tags,
                     deps = deps + variant_deps,
-                    plugins = plugins,
-                    javacopts = javacopts + variant_javacopts,
+                    plugins = merged_plugins,
+                    javacopts = merged_javacopts,
                     functional = functional,
                     require_jdk7_syntax = require_jdk7_syntax,
                 )
@@ -242,6 +243,7 @@
 
             for test_file in test_files:
                 test_name = test_file.rsplit(".", 1)[0]
+
                 _GenTestWithVariant(
                     library_rule_type = library_rule_type,
                     test_rule_type = test_rule_type,
@@ -249,8 +251,8 @@
                     srcs = [test_file],
                     tags = tags,
                     deps = test_deps + variant_deps,
-                    plugins = plugins,
-                    javacopts = javacopts + variant_javacopts,
+                    plugins = merged_plugins,
+                    javacopts = merged_javacopts,
                     shard_count = shard_count,
                     jvm_flags = jvm_flags,
                     functional = functional,
diff --git a/third_party/java/auto/BUILD b/third_party/java/auto/BUILD
index 93e7e5b..48ad091 100644
--- a/third_party/java/auto/BUILD
+++ b/third_party/java/auto/BUILD
@@ -26,7 +26,6 @@
 java_plugin(
     name = "auto_value_processor",
     processor_class = "com.google.auto.value.processor.AutoValueProcessor",
-    visibility = ["//visibility:private"],
     deps = [
         ":common",
         ":service",
diff --git a/third_party/kotlin/build_extensions/rules.bzl b/third_party/kotlin/build_extensions/rules.bzl
index f1d9b7c..14aa4ef 100644
--- a/third_party/kotlin/build_extensions/rules.bzl
+++ b/third_party/kotlin/build_extensions/rules.bzl
@@ -14,7 +14,7 @@
 
 """Convenience wrapper for kt_android_library."""
 
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", io_kt_android_library = "kt_android_library")
+load("@io_bazel_rules_kotlin//kotlin:android.bzl", io_kt_android_library = "kt_android_library")
 
 def kt_android_library(**kwargs):
     io_kt_android_library(**kwargs)
diff --git a/third_party/kotlin/kotlin_metadata_jvm/BUILD b/third_party/kotlin/kotlin_metadata_jvm/BUILD
new file mode 100644
index 0000000..6f19a2d
--- /dev/null
+++ b/third_party/kotlin/kotlin_metadata_jvm/BUILD
@@ -0,0 +1,22 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+# BUILD rules for https://github.com/square/kotlinpoet
+
+package(default_visibility = ["//:src"])
+
+alias(
+    name = "kotlin_metadata_jvm",
+    actual = "@maven//:org_jetbrains_kotlin_kotlin_metadata_jvm",
+)
diff --git a/tools/BUILD b/tools/BUILD
index 83d5048..035bdba 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -16,28 +16,9 @@
 #   Tools for Dagger
 
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load(":maven_info.bzl", "maven_info_tests")
 
 package(default_visibility = ["//:src"])
 
-maven_info_tests()
-
-exports_files([
-    "pom-template.xml",
-])
-
-bzl_library(
-    name = "maven_bzl",
-    srcs = ["maven.bzl"],
-    deps = [":maven_info_bzl"],
-)
-
-bzl_library(
-    name = "maven_info_bzl",
-    srcs = ["maven_info.bzl"],
-    deps = ["@bazel_skylib//lib:unittest"],
-)
-
 bzl_library(
     name = "dejetify_bzl",
     srcs = ["dejetify.bzl"],
diff --git a/tools/bazel.rc b/tools/bazel.rc
deleted file mode 100644
index 2707c1c..0000000
--- a/tools/bazel.rc
+++ /dev/null
@@ -1,11 +0,0 @@
-# Global bazelrc file (see https://bazel.build/run/bazelrc#global-bazelrc)
-
-# Note: This flag is required to prevent actions from clashing with each when
-# reading/writing tmp files. Without this flag we get errors like:
-#
-#  Error: Cannot use file /tmp/hsperfdata_runner/12 because it is locked by
-#         another process
-#
-# This flag will be enabled by default in Bazel 7.0.0, but for now we enable it
-# manually. For more details: https://github.com/bazelbuild/bazel/issues/3236.
-build --incompatible_sandbox_hermetic_tmp
\ No newline at end of file
diff --git a/tools/bazel_compat.bzl b/tools/bazel_compat.bzl
index bc8b04a..9660588 100644
--- a/tools/bazel_compat.bzl
+++ b/tools/bazel_compat.bzl
@@ -12,14 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Macros for building with Bazel.
-"""
+# Description:
+#    Macros for building with Bazel.
 
 load("//third_party/kotlin/build_extensions:rules.bzl", "kt_android_library")
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 
 def compat_kt_android_library(name, **kwargs):
     bazel_kt_android_library(name, kwargs)
 
+def compat_kt_jvm_library(name, **kwargs):
+    bazel_kt_jvm_library(name, kwargs)
+
 def bazel_kt_android_library(name, kwargs):
     """A macro that wraps Bazel's kt_android_library.
 
@@ -63,3 +67,24 @@
         name = "lib{}-src.jar".format(name),
         actual = ":{}_internal_kt-sources.jar".format(name),
     )
+
+def bazel_kt_jvm_library(name, kwargs):
+    """A macro that wraps Bazel's kt_jvm_library.
+
+    This macro wraps Bazel's kt_jvm_library to output the jars files
+    in the expected locations (https://github.com/bazelbuild/rules_kotlin/issues/324).
+
+    Args:
+      name: the name of the library.
+      kwargs: Additional arguments of the library.
+    """
+
+    kt_jvm_library(
+        name = name,
+        **kwargs
+    )
+
+    native.alias(
+        name = "lib{}-src.jar".format(name),
+        actual = ":{}-sources.jar".format(name),
+    )
diff --git a/tools/jarjar/BUILD b/tools/jarjar/BUILD
new file mode 100644
index 0000000..6bcfba0
--- /dev/null
+++ b/tools/jarjar/BUILD
@@ -0,0 +1,50 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+# Starlark rules for using jarjar
+
+load("@rules_java//java:defs.bzl", "java_binary")
+
+package(default_visibility = ["//:src"])
+
+java_binary(
+    name = "jarjar",
+    main_class = "org.pantsbuild.jarjar.Main",
+    visibility = ["//visibility:public"],
+    runtime_deps = [
+        "//third_party/java/asm",
+        "//third_party/java/asm:asm-commons",
+        "//third_party/java/asm:asm-tree",
+        "//third_party/java/jsr250_annotations",
+        "//third_party/java/jsr330_inject",
+        "@maven//:javax_enterprise_cdi_api",
+        "@maven//:org_apache_ant_ant",
+        "@maven//:org_apache_ant_ant_launcher",
+        "@maven//:org_apache_maven_maven_artifact",
+        "@maven//:org_apache_maven_maven_model",
+        "@maven//:org_apache_maven_maven_plugin_api",
+        "@maven//:org_codehaus_plexus_plexus_classworlds",
+        "@maven//:org_codehaus_plexus_plexus_component_annotations",
+        "@maven//:org_codehaus_plexus_plexus_utils",
+        "@maven//:org_eclipse_sisu_org_eclipse_sisu_inject",
+        "@maven//:org_eclipse_sisu_org_eclipse_sisu_plexus",
+        "@maven//:org_pantsbuild_jarjar",
+    ],
+)
+
+sh_binary(
+    name = "jarjar_runner",
+    srcs = ["jarjar_runner.sh"],
+    visibility = ["//visibility:public"],
+)
diff --git a/tools/jarjar/jarjar.bzl b/tools/jarjar/jarjar.bzl
new file mode 100644
index 0000000..2fa6554
--- /dev/null
+++ b/tools/jarjar/jarjar.bzl
@@ -0,0 +1,92 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+"""Skylark rules for jarjar. See https://github.com/pantsbuild/jarjar
+"""
+
+load("@rules_java//java:defs.bzl", "java_common")
+
+def _jarjar_library(ctx):
+    ctx.actions.write(
+        output = ctx.outputs._rules_file,
+        content = "\n".join(ctx.attr.rules),
+    )
+
+    jar_files = depset(transitive = [jar.files for jar in ctx.attr.jars]).to_list()
+
+    command = """
+        export JAVA_HOME="{java_home}"
+        export MERGE_META_INF_FILES="{merge_meta_inf_files}"
+        export JARJAR="{jarjar}"
+        export RULES_FILE="{rules_file}"
+        export OUTFILE="{outfile}"
+        "{jarjar_runner}" {jars}
+    """.format(
+        java_home = str(ctx.attr._jdk[java_common.JavaRuntimeInfo].java_home),
+        merge_meta_inf_files = " ".join(ctx.attr.merge_meta_inf_files),
+        jarjar = ctx.executable._jarjar.path,
+        rules_file = ctx.outputs._rules_file.path,
+        outfile = ctx.outputs.jar.path,
+        jarjar_runner = ctx.executable._jarjar_runner.path,
+        jars = " ".join([jar.path for jar in jar_files]),
+    )
+
+    ctx.actions.run_shell(
+        command = command,
+        inputs = [ctx.outputs._rules_file] + jar_files + ctx.files._jdk,
+        outputs = [ctx.outputs.jar],
+        tools = [ctx.executable._jarjar, ctx.executable._jarjar_runner],
+    )
+
+_jarjar_library_attrs = {
+    "rules": attr.string_list(),
+    "jars": attr.label_list(
+        allow_files = [".jar"],
+    ),
+    "merge_meta_inf_files": attr.string_list(
+        allow_empty = True,
+        default = [],
+        mandatory = False,
+        doc = """A list of regular expressions that match files relative to the
+        META-INF directory that will be merged into the output jar, in addition
+        to files in META-INF/services. To add all files in META-INF/foo, for
+        example, use "foo/.*".""",
+    ),
+}
+
+_jarjar_library_attrs.update({
+    "_jarjar": attr.label(
+        default = Label("//tools/jarjar"),
+        executable = True,
+        cfg = "exec",
+    ),
+    "_jarjar_runner": attr.label(
+        default = Label("//tools/jarjar:jarjar_runner"),
+        executable = True,
+        cfg = "exec",
+    ),
+    "_jdk": attr.label(
+        default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
+        providers = [java_common.JavaRuntimeInfo],
+    ),
+})
+
+jarjar_library = rule(
+    attrs = _jarjar_library_attrs,
+    outputs = {
+        "jar": "%{name}.jar",
+        "_rules_file": "%{name}.jarjar_rules",
+    },
+    implementation = _jarjar_library,
+)
diff --git a/tools/jarjar/jarjar_runner.sh b/tools/jarjar/jarjar_runner.sh
new file mode 100755
index 0000000..502fea0
--- /dev/null
+++ b/tools/jarjar/jarjar_runner.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+JAVA_HOME="$(cd "${JAVA_HOME}" && pwd)" # this is used outside of the root
+
+TMPDIR="$(mktemp -d)"
+for jar in "$@"; do
+  unzip -qq -B "${jar}" -d "${TMPDIR}"
+done
+
+pushd "${TMPDIR}" &>/dev/null
+
+find=(find)
+if [[ "$(uname -s)" == "Darwin" ]]; then
+  # Mac uses BSD find, which requires extra args for regex matching.
+  find+=(-E)
+  suffix='(~[0-9]*)?'
+else
+  # Default to GNU find, which must escape parentheses.
+  suffix='\(~[0-9]*\)?'
+fi
+
+# Concatenate similar files in META-INF that allow it.
+for meta_inf_pattern in services/.* ${MERGE_META_INF_FILES}; do
+  regex="META-INF/${meta_inf_pattern}${suffix}"
+  for file in $("${find[@]}" META-INF -regex "${regex}"); do
+    original="$(sed s/"~[0-9]*$"// <<< "${file}")"
+    if [[ "${file}" != "${original}" ]]; then
+      cat "${file}" >> "${original}"
+      rm "${file}"
+    fi
+  done
+done
+
+# build-data.properties is emitted by Bazel with target information that can
+# cause conflicts. Delete it since it doesn't make sense to keep in the merged
+# jar anyway.
+rm build-data.properties*
+rm META-INF/MANIFEST.MF*
+rm -rf META-INF/maven/
+duplicate_files="$(find * -type f -regex '.*~[0-9]*$')"
+if [[ -n "${duplicate_files}" ]]; then
+  echo "Error: duplicate files in merged jar: ${duplicate_files}"
+  exit 1
+fi
+"${JAVA_HOME}/bin/jar" cf combined.jar *
+
+popd &>/dev/null
+
+# If the RULES_FILE exists and is not empty then run jarjar.
+# Otherwise, we're done so just copy the combined jar to the output file.
+if [[ -f "${RULES_FILE}" && -s "${RULES_FILE}" ]]; then
+    "${JARJAR}" process "${RULES_FILE}" "${TMPDIR}/combined.jar" "${OUTFILE}"
+else
+    cp $TMPDIR/combined.jar $OUTFILE
+fi
+
+rm -rf "${TMPDIR}"
diff --git a/tools/jarjar/test/BUILD b/tools/jarjar/test/BUILD
new file mode 100644
index 0000000..42659e6
--- /dev/null
+++ b/tools/jarjar/test/BUILD
@@ -0,0 +1,43 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+# Starlark tests for jarjar
+
+load("//tools/jarjar:jarjar.bzl", "jarjar_library")
+
+# Test target used for validating rule.
+jarjar_library(
+    name = "test_target",
+    testonly = 1,
+    jars = [
+        ":test-library1.jar",
+        ":test-library2.jar",
+    ],
+    merge_meta_inf_files = ["utilities/libs.dep"],
+)
+
+# Test that validates jarjar with merged META-INF files.
+sh_test(
+    name = "validate_test_target",
+    srcs = [":jarjar_validator.sh"],
+    args = [
+        "$(location :test_target.jar)",
+        "utilities/libs.dep",
+        "$(location :expected_libs.dep)",
+    ],
+    data = [
+        ":expected_libs.dep",
+        ":test_target.jar",
+    ],
+)
diff --git a/tools/jarjar/test/expected_libs.dep b/tools/jarjar/test/expected_libs.dep
new file mode 100644
index 0000000..5e34c37
--- /dev/null
+++ b/tools/jarjar/test/expected_libs.dep
@@ -0,0 +1,2 @@
+Library2
+Library1
diff --git a/tools/jarjar/test/jarjar_validator.sh b/tools/jarjar/test/jarjar_validator.sh
new file mode 100755
index 0000000..ca64f9d
--- /dev/null
+++ b/tools/jarjar/test/jarjar_validator.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+if diff <(unzip -p "$1" "META-INF/$2") "$3"; then
+  echo Passed
+  exit 0
+else
+  echo Failed
+  exit 1
+fi
diff --git a/tools/jarjar/test/test-library1.jar b/tools/jarjar/test/test-library1.jar
new file mode 100644
index 0000000..418894f
--- /dev/null
+++ b/tools/jarjar/test/test-library1.jar
Binary files differ
diff --git a/tools/jarjar/test/test-library2.jar b/tools/jarjar/test/test-library2.jar
new file mode 100644
index 0000000..072cb62
--- /dev/null
+++ b/tools/jarjar/test/test-library2.jar
Binary files differ
diff --git a/tools/javadoc/BUILD b/tools/javadoc/BUILD
new file mode 100644
index 0000000..9355350
--- /dev/null
+++ b/tools/javadoc/BUILD
@@ -0,0 +1,17 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+# Starlark rules for generating Javadoc
+
+package(default_visibility = ["//:src"])
diff --git a/tools/javadoc/javadoc.bzl b/tools/javadoc/javadoc.bzl
new file mode 100644
index 0000000..db7eccd
--- /dev/null
+++ b/tools/javadoc/javadoc.bzl
@@ -0,0 +1,156 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+"""See javadoc_library."""
+
+load("@rules_java//java:defs.bzl", "JavaInfo", "java_common")
+
+def _android_jar(android_api_level):
+    if android_api_level == -1:
+        return None
+    return Label("@androidsdk//:platforms/android-%s/android.jar" % android_api_level)
+
+def _javadoc_library(ctx):
+    transitive_deps = []
+    for dep in ctx.attr.deps:
+        if JavaInfo in dep:
+            transitive_deps.append(dep[JavaInfo].transitive_compile_time_jars)
+
+    if ctx.attr._android_jar:
+        transitive_deps.append(ctx.attr._android_jar.files)
+
+    classpath = depset([], transitive = transitive_deps).to_list()
+
+    java_home = str(ctx.attr._jdk[java_common.JavaRuntimeInfo].java_home)
+
+    output_dir = ctx.actions.declare_directory("%s_javadoc" % ctx.attr.name)
+
+    javadoc_arguments = ctx.actions.args()
+    javadoc_arguments.use_param_file("@%s", use_always = True)
+    javadoc_arguments.set_param_file_format("multiline")
+
+    javadoc_command = java_home + "/bin/javadoc"
+
+    javadoc_arguments.add("-use")
+    javadoc_arguments.add("-encoding", "UTF8")
+    javadoc_arguments.add_joined("-classpath", classpath, join_with = ":")
+    javadoc_arguments.add("-notimestamp")
+    javadoc_arguments.add("-d", output_dir.path)
+    javadoc_arguments.add("-Xdoclint:-missing")
+    javadoc_arguments.add("-quiet")
+
+    # Documentation for the javadoc command
+    # https://docs.oracle.com/javase/9/javadoc/javadoc-command.htm
+    if ctx.attr.root_packages:
+        # TODO(b/167433657): Reevaluate the utility of root_packages
+        # 1. Find the first directory under the working directory named '*java'.
+        # 2. Assume all files to document can be found by appending a root_package name
+        #    to that directory, or a subdirectory, replacing dots with slashes.
+        javadoc_command += ' -sourcepath $(find * -type d -name "*java" -print0 | tr "\\0" :) '
+        javadoc_arguments.add_all(ctx.attr.root_packages)
+        javadoc_arguments.add_joined("-subpackages", ctx.attr.root_packages, join_with = ":")
+    else:
+        # Document exactly the code in the specified source files.
+        javadoc_arguments.add_all(ctx.files.srcs)
+
+    if ctx.attr.doctitle:
+        javadoc_arguments.add("-doctitle", ctx.attr.doctitle, format = '"%s"')
+
+    if ctx.attr.groups:
+        groups = []
+        for k, v in ctx.attr.groups.items():
+            groups.append("-group \"%s\" \"%s\"" % (k, ":".join(v)))
+        javadoc_arguments.add_all(groups)
+
+    javadoc_arguments.add_joined("-exclude", ctx.attr.exclude_packages, join_with = ":")
+
+    javadoc_arguments.add_all(
+        ctx.attr.external_javadoc_links,
+        map_each = _format_linkoffline_value,
+    )
+
+    if ctx.attr.bottom_text:
+        javadoc_arguments.add("-bottom", ctx.attr.bottom_text, format = '"%s"')
+
+    # TODO(ronshapiro): Should we be using a different tool that doesn't include
+    # timestamp info?
+    jar_command = "%s/bin/jar cf %s -C %s ." % (java_home, ctx.outputs.jar.path, output_dir.path)
+
+    srcs = depset(transitive = [src.files for src in ctx.attr.srcs]).to_list()
+    ctx.actions.run_shell(
+        inputs = srcs + classpath + ctx.files._jdk,
+        command = "%s $@ && %s" % (javadoc_command, jar_command),
+        arguments = [javadoc_arguments],
+        outputs = [output_dir, ctx.outputs.jar],
+    )
+
+def _format_linkoffline_value(link):
+    return "-linkoffline {0} {0}".format(link)
+
+javadoc_library = rule(
+    attrs = {
+        "srcs": attr.label_list(
+            allow_empty = False,
+            allow_files = True,
+            doc = "Source files to generate Javadoc for.",
+        ),
+        "deps": attr.label_list(
+            doc = """
+Targets that contain references to other types referenced in Javadoc. These can
+be the java_library/android_library target(s) for the same sources.
+""",
+        ),
+        "doctitle": attr.string(
+            default = "",
+            doc = "Title for generated index.html. See javadoc -doctitle.",
+        ),
+       "groups": attr.string_list_dict(
+          doc = "Groups specified packages together in overview page. See javadoc -groups.",
+       ),
+        "root_packages": attr.string_list(
+            doc = """
+Java packages to include in generated Javadoc. Any subpackages not listed in
+exclude_packages will be included as well. If none are provided, each file in
+`srcs` is processed.
+""",
+        ),
+        "exclude_packages": attr.string_list(
+            doc = "Java packages to exclude from generated Javadoc.",
+        ),
+        "android_api_level": attr.int(
+            default = -1,
+            doc = """
+If Android APIs are used, the API level to compile against to generate Javadoc.
+""",
+        ),
+        "bottom_text": attr.string(
+            default = "",
+            doc = "Text passed to Javadoc's `-bottom` flag.",
+        ),
+        "external_javadoc_links": attr.string_list(
+            doc = "URLs passed to Javadoc's `-linkoffline` flag.",
+        ),
+        "_android_jar": attr.label(
+            default = _android_jar,
+            allow_single_file = True,
+        ),
+        "_jdk": attr.label(
+            default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
+            providers = [java_common.JavaRuntimeInfo],
+        ),
+    },
+    outputs = {"jar": "%{name}.jar"},
+    doc = "Generates a Javadoc jar path/to/target/<name>.jar.",
+    implementation = _javadoc_library,
+)
diff --git a/tools/maven/BUILD b/tools/maven/BUILD
new file mode 100644
index 0000000..d92397e
--- /dev/null
+++ b/tools/maven/BUILD
@@ -0,0 +1,45 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+
+# Starlark rules for generating Maven pom files
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load(":maven_info.bzl", "maven_info_tests")
+load(":pom_file.bzl", "pom_file_tests")
+
+package(default_visibility = ["//:src"])
+
+exports_files(["pom-template.xml"])
+
+bzl_library(
+    name = "maven_bzl",
+    srcs = ["maven.bzl"],
+    deps = [
+        ":maven_info_bzl",
+        "@rules_java//java:rules",
+    ],
+)
+
+bzl_library(
+    name = "maven_info_bzl",
+    srcs = ["maven_info.bzl"],
+    deps = [
+        "@bazel_skylib//lib:unittest",
+        "@rules_java//java:rules",
+    ],
+)
+
+maven_info_tests()
+
+pom_file_tests()
diff --git a/tools/maven.bzl b/tools/maven/maven.bzl
similarity index 97%
rename from tools/maven.bzl
rename to tools/maven/maven.bzl
index 4fba1a5..3177344 100644
--- a/tools/maven.bzl
+++ b/tools/maven/maven.bzl
@@ -11,29 +11,29 @@
 # 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.
-
 """Macros to simplify generating maven files.
 """
 
-load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-load("@google_bazel_common//tools/maven:pom_file.bzl", default_pom_file = "pom_file")
+load("@rules_java//java:defs.bzl", "java_binary")
+load("//tools/jarjar:jarjar.bzl", "jarjar_library")
+load("//tools/javadoc:javadoc.bzl", "javadoc_library")
 load(":maven_info.bzl", "MavenInfo", "collect_maven_info")
+load(":pom_file.bzl", "pom_file")
 
 SHADED_MAVEN_DEPS = [
     "com.google.auto:auto-common",
-    "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
+    "org.jetbrains.kotlin:kotlin-metadata-jvm",
 ]
 
-def pom_file(name, targets, artifact_name, artifact_id, packaging = None, **kwargs):
-    default_pom_file(
+def dagger_pom_file(name, targets, artifact_name, artifact_id, packaging = None, **kwargs):
+    pom_file(
         name = name,
         targets = targets,
         preferred_group_ids = [
             "com.google.dagger",
             "com.google",
         ],
-        template_file = "//tools:pom-template.xml",
+        template_file = "//tools/maven:pom-template.xml",
         substitutions = {
             "{artifact_name}": artifact_name,
             "{artifact_id}": artifact_id,
@@ -174,7 +174,7 @@
     ]
 
     artifact_id = artifact_coordinates.split(":")[1]
-    pom_file(
+    dagger_pom_file(
         name = pom_name,
         testonly = testonly,
         artifact_id = artifact_id,
@@ -290,7 +290,7 @@
         # Build an empty javadoc because Sonatype requires javadocs
         # even if the jar is empty.
         # https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources
-        native.java_binary(
+        java_binary(
             name = name + "-javadoc",
         )
 
diff --git a/tools/maven_info.bzl b/tools/maven/maven_info.bzl
similarity index 98%
rename from tools/maven_info.bzl
rename to tools/maven/maven_info.bzl
index 5ebed3f..c215d88 100644
--- a/tools/maven_info.bzl
+++ b/tools/maven/maven_info.bzl
@@ -14,6 +14,7 @@
 """Skylark rules to collect Maven artifacts information.
 """
 
+load("@rules_java//java:defs.bzl", "java_library")
 load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
 
 # TODO(b/142057516): Unfork this file once we've settled on a more general API.
@@ -105,7 +106,7 @@
         outs = src_file,
         cmd = "echo 'package pkg; class %s {}' > $@" % name,
     )
-    native.java_library(
+    java_library(
         name = name,
         srcs = src_file,
         tags = ["maven_coordinates=%s:_:_" % name] if is_artifact else [],
diff --git a/tools/pom-template.xml b/tools/maven/pom-template.xml
similarity index 100%
rename from tools/pom-template.xml
rename to tools/maven/pom-template.xml
diff --git a/tools/maven/pom_file.bzl b/tools/maven/pom_file.bzl
new file mode 100644
index 0000000..52d32b1
--- /dev/null
+++ b/tools/maven/pom_file.bzl
@@ -0,0 +1,361 @@
+# Copyright (C) 2024 The Dagger 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
+#
+# 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.
+"""Skylark rules to make publishing Maven artifacts simpler.
+"""
+
+load("@rules_java//java:defs.bzl", "java_library")
+load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
+
+MavenInfo = provider(
+    fields = {
+        "maven_artifacts": """
+        The Maven coordinates for the artifacts that are exported by this target: i.e. the target
+        itself and its transitively exported targets.
+        """,
+        "maven_dependencies": """
+        The Maven coordinates of the direct dependencies, and the transitively exported targets, of
+        this target.
+        """,
+    },
+)
+
+_EMPTY_MAVEN_INFO = MavenInfo(
+    maven_artifacts = depset(),
+    maven_dependencies = depset(),
+)
+
+_MAVEN_COORDINATES_PREFIX = "maven_coordinates="
+
+def _maven_artifacts(targets):
+    return [target[MavenInfo].maven_artifacts for target in targets if MavenInfo in target]
+
+def _collect_maven_info_impl(_target, ctx):
+    tags = getattr(ctx.rule.attr, "tags", [])
+    deps = getattr(ctx.rule.attr, "deps", [])
+    exports = getattr(ctx.rule.attr, "exports", [])
+    runtime_deps = getattr(ctx.rule.attr, "runtime_deps", [])
+
+    maven_artifacts = []
+    for tag in tags:
+        if tag in ("maven:compile_only", "maven:shaded"):
+            return [_EMPTY_MAVEN_INFO]
+        if tag.startswith(_MAVEN_COORDINATES_PREFIX):
+            maven_artifacts.append(tag[len(_MAVEN_COORDINATES_PREFIX):])
+
+    return [MavenInfo(
+        maven_artifacts = depset(maven_artifacts, transitive = _maven_artifacts(exports)),
+        maven_dependencies = depset(
+            [],
+            transitive = _maven_artifacts(deps + exports + runtime_deps),
+        ),
+    )]
+
+_collect_maven_info = aspect(
+    attr_aspects = [
+        "deps",
+        "exports",
+        "runtime_deps",
+    ],
+    doc = """
+    Collects the Maven information for targets, their dependencies, and their transitive exports.
+    """,
+    implementation = _collect_maven_info_impl,
+)
+
+def _prefix_index_of(item, prefixes):
+    """Returns the index of the first value in `prefixes` that is a prefix of `item`.
+
+    If none of the prefixes match, return the size of `prefixes`.
+
+    Args:
+      item: the item to match
+      prefixes: prefixes to match against
+
+    Returns:
+      an integer representing the index of the match described above.
+    """
+    for index, prefix in enumerate(prefixes):
+        if item.startswith(prefix):
+            return index
+    return len(prefixes)
+
+def _sort_artifacts(artifacts, prefixes):
+    """Sorts `artifacts`, preferring group ids that appear earlier in `prefixes`.
+
+    Values in `prefixes` do not need to be complete group ids. For example, passing `prefixes =
+    ['io.bazel']` will match `io.bazel.rules:rules-artifact:1.0`. If multiple prefixes match an
+    artifact, the first one in `prefixes` will be used.
+
+    _Implementation note_: Skylark does not support passing a comparator function to the `sorted()`
+    builtin, so this constructs a list of tuples with elements:
+      - `[0]` = an integer corresponding to the index in `prefixes` that matches the artifact (see
+        `_prefix_index_of`)
+      - `[1]` = parts of the complete artifact, split on `:`. This is used as a tiebreaker when
+        multilple artifacts have the same index referenced in `[0]`. The individual parts are used so
+        that individual artifacts in the same group are sorted correctly - if just the string is used,
+        the colon that separates the artifact name from the version will sort lower than a longer
+        name. For example:
+        -  `com.example.project:base:1
+        -  `com.example.project:extension:1
+        "base" sorts lower than "exension".
+      - `[2]` = the complete artifact. this is a convenience so that after sorting, the artifact can
+      be returned.
+
+    The `sorted` builtin will first compare the index element and if it needs a tiebreaker, will
+    recursively compare the contents of the second element.
+
+    Args:
+      artifacts: artifacts to be sorted
+      prefixes: the preferred group ids used to sort `artifacts`
+
+    Returns:
+      A new, sorted list containing the contents of `artifacts`.
+    """
+    indexed = []
+    for artifact in artifacts:
+        parts = artifact.split(":")
+        indexed.append((_prefix_index_of(parts[0], prefixes), parts, artifact))
+
+    return [x[-1] for x in sorted(indexed)]
+
+DEP_BLOCK = """
+<dependency>
+  <groupId>{0}</groupId>
+  <artifactId>{1}</artifactId>
+  <version>{2}</version>
+</dependency>
+""".strip()
+
+CLASSIFIER_DEP_BLOCK = """
+<dependency>
+  <groupId>{0}</groupId>
+  <artifactId>{1}</artifactId>
+  <version>{2}</version>
+  <type>{3}</type>
+  <classifier>{4}</classifier>
+</dependency>
+""".strip()
+
+DEP_PKG_BLOCK = """
+<dependency>
+  <groupId>{0}</groupId>
+  <artifactId>{1}</artifactId>
+  <packaging>{2}</packaging>
+  <version>{3}</version>
+</dependency>
+""".strip()
+
+def _pom_file(ctx):
+    mvn_deps = depset(
+        [],
+        transitive = [target[MavenInfo].maven_dependencies for target in ctx.attr.targets],
+    )
+
+    formatted_deps = []
+    for dep in _sort_artifacts(mvn_deps.to_list(), ctx.attr.preferred_group_ids):
+        parts = dep.split(":")
+        if ":".join(parts[0:2]) in ctx.attr.excluded_artifacts:
+            continue
+        if len(parts) == 3:
+            template = DEP_BLOCK
+        elif len(parts) == 4:
+            template = DEP_PKG_BLOCK
+        elif len(parts) == 5:
+            template = CLASSIFIER_DEP_BLOCK
+        else:
+            fail("Unknown dependency format: %s" % dep)
+
+        formatted_deps.append(template.format(*parts))
+
+    substitutions = {}
+    substitutions.update(ctx.attr.substitutions)
+    substitutions.update({
+        "{generated_bzl_deps}": "\n".join(formatted_deps),
+        "{pom_version}": ctx.var.get("pom_version", "LOCAL-SNAPSHOT"),
+    })
+
+    ctx.actions.expand_template(
+        template = ctx.file.template_file,
+        output = ctx.outputs.pom_file,
+        substitutions = substitutions,
+    )
+
+pom_file = rule(
+    attrs = {
+        "template_file": attr.label(
+            allow_single_file = True,
+        ),
+        "substitutions": attr.string_dict(
+            allow_empty = True,
+            mandatory = False,
+        ),
+        "targets": attr.label_list(
+            mandatory = True,
+            aspects = [_collect_maven_info],
+        ),
+        "preferred_group_ids": attr.string_list(),
+        "excluded_artifacts": attr.string_list(),
+    },
+    doc = """
+    Creates a Maven POM file for `targets`.
+
+    This rule scans the deps, runtime_deps, and exports of `targets` and their transitive exports,
+    checking each for tags of the form `maven_coordinates=<coords>`. These tags are used to build
+    the list of Maven dependencies for the generated POM.
+
+    Users should call this rule with a `template_file` that contains a `{generated_bzl_deps}`
+    placeholder. The rule will replace this with the appropriate XML for all dependencies.
+    Additional placeholders to replace can be passed via the `substitutions` argument.
+
+    The dependencies included will be sorted alphabetically by groupId, then by artifactId. The
+    `preferred_group_ids` can be used to specify groupIds (or groupId-prefixes) that should be
+    sorted ahead of other artifacts. Artifacts in the same group will be sorted alphabetically.
+
+    Args:
+      name: the name of target. The generated POM file will use this name, with `.xml` appended
+      targets: a list of build target(s) that represent this POM file
+      template_file: a pom.xml file that will be used as a template for the generated POM
+      substitutions: an optional mapping of placeholders to replacement values that will be applied
+        to the `template_file` (e.g. `{'GROUP_ID': 'com.example.group'}`). `{pom_version}` is
+        implicitly included in this mapping and can be configured by passing `bazel build
+        --define=pom_version=<version>`.
+      preferred_group_ids: an optional list of maven groupIds that will be used to sort the
+        generated deps.
+      excluded_artifacts: an optional list of maven artifacts in the format "groupId:artifactId"
+        that should be excluded from the generated pom file.
+    """,
+    outputs = {"pom_file": "%{name}.xml"},
+    implementation = _pom_file,
+)
+
+def _fake_java_library(name, deps = None, exports = None, runtime_deps = None):
+    src_file = ["%s.java" % name]
+    native.genrule(
+        name = "%s_source_file" % name,
+        outs = src_file,
+        cmd = "echo 'class %s {}' > $@" % name,
+    )
+    java_library(
+        name = name,
+        srcs = src_file,
+        tags = ["maven_coordinates=%s:_:_" % name],
+        javacopts = ["-Xep:DefaultPackage:OFF"],
+        deps = deps or [],
+        exports = exports or [],
+        runtime_deps = runtime_deps or [],
+    )
+
+def _maven_info_test_impl(ctx):
+    env = unittest.begin(ctx)
+    asserts.equals(
+        env,
+        expected = sorted(ctx.attr.maven_artifacts),
+        actual = sorted(ctx.attr.target[MavenInfo].maven_artifacts.to_list()),
+        msg = "MavenInfo.maven_artifacts",
+    )
+    asserts.equals(
+        env,
+        expected = sorted(ctx.attr.maven_dependencies),
+        actual = sorted(ctx.attr.target[MavenInfo].maven_dependencies.to_list()),
+        msg = "MavenInfo.maven_dependencies",
+    )
+    return unittest.end(env)
+
+_maven_info_test = unittest.make(
+    _maven_info_test_impl,
+    attrs = {
+        "target": attr.label(aspects = [_collect_maven_info]),
+        "maven_artifacts": attr.string_list(),
+        "maven_dependencies": attr.string_list(),
+    },
+)
+
+def pom_file_tests():
+    """Tests for `pom_file` and `MavenInfo`.
+    """
+    _fake_java_library(name = "FileA")
+    _maven_info_test(
+        name = "FileA_test",
+        target = ":FileA",
+        maven_artifacts = ["FileA:_:_"],
+        maven_dependencies = [],
+    )
+
+    _fake_java_library(
+        name = "DepOnFileA",
+        deps = [":FileA"],
+    )
+    _maven_info_test(
+        name = "DepOnFileA_test",
+        target = ":DepOnFileA",
+        maven_artifacts = ["DepOnFileA:_:_"],
+        maven_dependencies = ["FileA:_:_"],
+    )
+
+    _fake_java_library(
+        name = "RuntimeDepOnFileA",
+        runtime_deps = [":FileA"],
+    )
+    _maven_info_test(
+        name = "RuntimeDepOnFileA_test",
+        target = ":RuntimeDepOnFileA",
+        maven_artifacts = ["RuntimeDepOnFileA:_:_"],
+        maven_dependencies = ["FileA:_:_"],
+    )
+
+    _fake_java_library(
+        name = "ExportsFileA",
+        exports = [":FileA"],
+    )
+    _maven_info_test(
+        name = "ExportsFileA_test",
+        target = ":ExportsFileA",
+        maven_artifacts = [
+            "ExportsFileA:_:_",
+            "FileA:_:_",
+        ],
+        maven_dependencies = ["FileA:_:_"],
+    )
+
+    _fake_java_library(
+        name = "TransitiveExportsFileA",
+        exports = [":ExportsFileA"],
+    )
+    _maven_info_test(
+        name = "TransitiveExportsFileA_test",
+        target = ":TransitiveExportsFileA",
+        maven_artifacts = [
+            "TransitiveExportsFileA:_:_",
+            "ExportsFileA:_:_",
+            "FileA:_:_",
+        ],
+        maven_dependencies = [
+            "ExportsFileA:_:_",
+            "FileA:_:_",
+        ],
+    )
+
+    _fake_java_library(
+        name = "TransitiveDepsFileA",
+        deps = [":ExportsFileA"],
+    )
+    _maven_info_test(
+        name = "TransitiveDepsFileA_test",
+        target = ":TransitiveDepsFileA",
+        maven_artifacts = ["TransitiveDepsFileA:_:_"],
+        maven_dependencies = [
+            "ExportsFileA:_:_",
+            "FileA:_:_",
+        ],
+    )
diff --git a/tools/shader/gradle/wrapper/gradle-wrapper.properties b/tools/shader/gradle/wrapper/gradle-wrapper.properties
index 0f80bbf..e1bef7e 100644
--- a/tools/shader/gradle/wrapper/gradle-wrapper.properties
+++ b/tools/shader/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/tools/shader/settings.gradle b/tools/shader/settings.gradle
new file mode 100644
index 0000000..3edfbdb
--- /dev/null
+++ b/tools/shader/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "shader"
\ No newline at end of file
diff --git a/util/build-gradle.sh b/util/build-gradle.sh
new file mode 100755
index 0000000..c01ce7a
--- /dev/null
+++ b/util/build-gradle.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+set -ex
+
+./gradlew build --no-daemon --stacktrace
\ No newline at end of file
diff --git a/util/deploy-dagger.sh b/util/deploy-dagger.sh
index b0b68a8..0f258c8 100755
--- a/util/deploy-dagger.sh
+++ b/util/deploy-dagger.sh
@@ -52,7 +52,7 @@
   ""
 
 _deploy \
-  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.internal.shaded.kotlinx.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
+  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlin.metadata,dagger.spi.internal.shaded.kotlin.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
   java/dagger/internal/codegen/artifact.jar \
   java/dagger/internal/codegen/pom.xml \
   java/dagger/internal/codegen/artifact-src.jar \
@@ -68,7 +68,7 @@
   ""
 
 _deploy \
-  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.internal.shaded.kotlinx.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
+  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlin.metadata,dagger.spi.internal.shaded.kotlin.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
   java/dagger/spi/artifact.jar \
   java/dagger/spi/pom.xml \
   java/dagger/spi/artifact-src.jar \
@@ -108,7 +108,7 @@
   ""
 
 _deploy \
-  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.internal.shaded.kotlinx.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
+  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlin.metadata,dagger.spi.internal.shaded.kotlin.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
   java/dagger/android/processor/artifact.jar \
   java/dagger/android/processor/pom.xml \
   java/dagger/android/processor/artifact-src.jar \
diff --git a/util/deploy-hilt.sh b/util/deploy-hilt.sh
index 81b384c..99e314c 100755
--- a/util/deploy-hilt.sh
+++ b/util/deploy-hilt.sh
@@ -52,7 +52,7 @@
   ""
 
 _deploy \
-  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.internal.shaded.kotlinx.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
+  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlin.metadata,dagger.spi.internal.shaded.kotlin.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
   java/dagger/hilt/processor/artifact.jar \
   java/dagger/hilt/processor/pom.xml \
   java/dagger/hilt/processor/artifact-src.jar \
@@ -60,7 +60,7 @@
   ""
 
 _deploy \
-  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.internal.shaded.kotlinx.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
+  "com.google.auto.common,dagger.spi.internal.shaded.auto.common;androidx.room.compiler,dagger.spi.internal.shaded.androidx.room.compiler;kotlin.metadata,dagger.spi.internal.shaded.kotlin.metadata;androidx.room,dagger.spi.internal.shaded.androidx.room" \
   java/dagger/hilt/android/processor/artifact.jar \
   java/dagger/hilt/android/processor/pom.xml \
   java/dagger/hilt/android/processor/artifact-src.jar \
diff --git a/util/deploy-library.sh b/util/deploy-library.sh
index 35c566b..0296294 100755
--- a/util/deploy-library.sh
+++ b/util/deploy-library.sh
@@ -33,9 +33,6 @@
     library="${library%.*}-shaded.${library##*.}"
   fi
 
-  # Validate that the classes in the library jar begin with expected prefixes.
-  validate_jar $(bazel_output_file $library)
-
   # TODO(bcorso): Consider moving this into the "gen_maven_artifact" macro, this
   # requires having the version checked-in for the build system.
   add_tracking_version \
@@ -101,20 +98,6 @@
   fi
 }
 
-validate_jar() {
-  local library=$1
-  if [[ $library == */gwt/libgwt.jar ]]; then
-     python $(dirname $0)/validate-jar-entry-prefixes.py \
-        $library "dagger/,META-INF/,javax/inject/"
-  elif [[ $library == */java/dagger/hilt/android/artifact.aar ]]; then
-     python $(dirname $0)/validate-jar-entry-prefixes.py \
-        $library "dagger/,META-INF/,hilt_aggregated_deps/"
-  else
-     python $(dirname $0)/validate-jar-entry-prefixes.py \
-        $library "dagger/,META-INF/"
-  fi
-}
-
 add_automatic_module_name_manifest_entry() {
   local library=$1
   local module_name=$2
diff --git a/util/run-local-gradle-android-tests.sh b/util/run-local-gradle-android-tests.sh
index 9ae56f8..1691313 100755
--- a/util/run-local-gradle-android-tests.sh
+++ b/util/run-local-gradle-android-tests.sh
@@ -7,35 +7,23 @@
 
 readonly JAVA_ANDROID_GRADLE_PROJECTS=(
     "javatests/artifacts/dagger-android/simple"
+    "javatests/artifacts/dagger-android-ksp"
     "javatests/artifacts/hilt-android/simple"
+    "javatests/artifacts/hilt-android/pluginMarker"
 )
 readonly KOTLIN_ANDROID_GRADLE_PROJECTS=(
     "javatests/artifacts/hilt-android/simpleKotlin"
 )
-if [[ $AGP_VERSION_INPUT == "7.0.0" || $AGP_VERSION_INPUT == "7.1.2" ]]
-then
-  for project in "${JAVA_ANDROID_GRADLE_PROJECTS[@]}"; do
-      echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue $COMMON_GRADLE_ARGS
-  done
 
-  for project in "${KOTLIN_ANDROID_GRADLE_PROJECTS[@]}"; do
-      echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKaptDebugUnitTest --continue $COMMON_GRADLE_ARGS
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKspDebugUnitTest --continue $COMMON_GRADLE_ARGS
-  done
-fi
+for project in "${JAVA_ANDROID_GRADLE_PROJECTS[@]}"; do
+    echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
+    AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
+    AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebugUnitTest --continue $COMMON_GRADLE_ARGS
+done
 
-readonly JAVA_ANDROID_GRADLE_JDK17_PROJECTS=(
-    "javatests/artifacts/dagger-android-ksp"
-)
-if [[ $AGP_VERSION_INPUT == "8.1.0" ]]
-then
-  for project in "${JAVA_ANDROID_GRADLE_JDK17_PROJECTS[@]}"; do
-      echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
-      AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue $COMMON_GRADLE_ARGS
-  done
-fi
+for project in "${KOTLIN_ANDROID_GRADLE_PROJECTS[@]}"; do
+    echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
+    AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
+    AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKaptDebugUnitTest --continue $COMMON_GRADLE_ARGS
+    AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKspDebugUnitTest --continue $COMMON_GRADLE_ARGS
+done
diff --git a/util/run-local-gradle-tests.sh b/util/run-local-gradle-tests.sh
index bb0c458..fca6882 100755
--- a/util/run-local-gradle-tests.sh
+++ b/util/run-local-gradle-tests.sh
@@ -5,7 +5,6 @@
 readonly GRADLE_PROJECTS=(
     "javatests/artifacts/dagger"
     "javatests/artifacts/dagger-ksp"
-    "javatests/artifacts/hilt-android/pluginMarker"
 )
 for project in "${GRADLE_PROJECTS[@]}"; do
     echo "Running gradle tests for $project"
diff --git a/util/run-local-tests.sh b/util/run-local-tests.sh
index 2603346..d79c8e4 100755
--- a/util/run-local-tests.sh
+++ b/util/run-local-tests.sh
@@ -16,7 +16,6 @@
 
 # Run local gradle tests
 util/run-local-gradle-tests.sh
-util/run-local-gradle-android-tests.sh "7.0.0"
-util/run-local-gradle-android-tests.sh "7.1.2"
+util/run-local-gradle-android-tests.sh "8.1.1"
 
 # TODO: this script is not up-to-date with Dagger github actions
diff --git a/util/validate-artifacts.sh b/util/validate-artifacts.sh
new file mode 100755
index 0000000..b556549
--- /dev/null
+++ b/util/validate-artifacts.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+set -eu
+
+readonly M2_DAGGER_REPO=~/.m2/repository/com/google/dagger
+readonly JDK8="52"
+
+_validate_jar() {
+  local artifact_id=$1
+  local artifact_jar=$M2_DAGGER_REPO/$1/LOCAL-SNAPSHOT/$1-LOCAL-SNAPSHOT.$2
+  local java_language_level=$3
+
+  # Validate the java language level of the classes in the jar.
+  python $(dirname $0)/validate-jar-language-level.py \
+      $artifact_jar $java_language_level
+
+  # Validate the package prefixes of the files in the jar.
+  if [[ $artifact_id == "dagger-gwt" ]]; then
+     python $(dirname $0)/validate-jar-entry-prefixes.py \
+        $artifact_jar "dagger/,META-INF/,javax/inject/Inject.gwt.xml,jakarta/inject/Inject.gwt.xml,org/jspecify/Jspecify.gwt.xml"
+  elif [[ $artifact_id == "hilt-android" ]]; then
+     python $(dirname $0)/validate-jar-entry-prefixes.py \
+        $artifact_jar "dagger/,META-INF/,hilt_aggregated_deps/"
+  else
+     python $(dirname $0)/validate-jar-entry-prefixes.py \
+        $artifact_jar "dagger/,META-INF/"
+  fi
+}
+
+# Dagger API artifacts
+_validate_jar "dagger-gwt" "jar" $JDK8
+_validate_jar "dagger" "jar" $JDK8
+_validate_jar "dagger-android" "aar" $JDK8
+_validate_jar "dagger-android-legacy" "aar" $JDK8
+_validate_jar "dagger-android-support" "aar" $JDK8
+_validate_jar "dagger-android-support-legacy" "aar" $JDK8
+_validate_jar "dagger-producers" "jar" $JDK8
+_validate_jar "dagger-grpc-server" "jar" $JDK8
+_validate_jar "dagger-grpc-server-annotations" "jar" $JDK8
+_validate_jar "dagger-lint" "jar" $JDK8
+_validate_jar "dagger-lint-aar" "aar" $JDK8
+
+# Hilt API artifacts
+# TODO(bcorso): reenable hilt-android-gradle-plugin validation.
+# _validate_jar "hilt-android-gradle-plugin" "jar" $JDK8
+_validate_jar "hilt-core" "jar" $JDK8
+_validate_jar "hilt-android" "aar" $JDK8
+_validate_jar "hilt-android-testing" "aar" $JDK8
+
+# Processor artifacts
+_validate_jar "dagger-spi" "jar" $JDK8
+_validate_jar "dagger-compiler" "jar" $JDK8
+_validate_jar "dagger-android-processor" "jar" $JDK8
+_validate_jar "dagger-grpc-server-processor" "jar" $JDK8
+_validate_jar "hilt-compiler" "jar" $JDK8
+_validate_jar "hilt-android-compiler" "jar" $JDK8
\ No newline at end of file
diff --git a/util/validate-jar-language-level.py b/util/validate-jar-language-level.py
new file mode 100644
index 0000000..ef8afed
--- /dev/null
+++ b/util/validate-jar-language-level.py
@@ -0,0 +1,109 @@
+"""Validates classes in the deployed jar have a max java language level .
+
+Usage:
+  python validate-jar-language-level.py <jar-file> <max-java-language-level>
+"""
+
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+
+_LANGUAGE_LEVEL_PATTERN = re.compile(r'major version: (\d+)')
+
+
+def main(argv):
+  if len(argv) > 3:
+    raise ValueError(
+        'Expected only two arguments but got {0}'.format(len(argv))
+    )
+
+  jar_file, expected_language_level = argv[-2:]
+  print(
+      'Processing {0} with expected language level {1}...'.format(
+          jar_file,
+          expected_language_level
+      )
+  )
+  if jar_file.endswith('.jar'):
+    invalid_entries = _invalid_language_level(jar_file, expected_language_level)
+  elif jar_file.endswith('.aar'):
+    dirpath = tempfile.mkdtemp()
+    with zipfile.ZipFile(jar_file, 'r') as zip_file:
+      class_file = zip_file.extract('classes.jar', dirpath)
+      invalid_entries = _invalid_language_level(
+          class_file,
+          expected_language_level
+      )
+    shutil.rmtree(dirpath)
+  else:
+    raise ValueError('Invalid jar file: {0}'.format(jar_file))
+
+  if invalid_entries:
+    raise ValueError(
+        'Found invalid entries in {0} that do not match the expected java'
+        ' language level ({1}):\n    {2}'.format(
+            jar_file, expected_language_level, '\n    '.join(invalid_entries)
+        )
+    )
+
+
+def _invalid_language_level(jar_file, expected_language_level):
+  """Returns a list of jar entries with invalid language levels."""
+  invalid_entries = []
+  with zipfile.ZipFile(jar_file, 'r') as zip_file:
+    class_infolist = [
+        info for info in zip_file.infolist()
+        if (
+            not info.is_dir()
+            and info.filename.endswith('.class')
+            and not is_shaded_class(info.filename)
+        )
+    ]
+    num_classes = len(class_infolist)
+    for i, info in enumerate(class_infolist):
+      cmd = 'javap -cp {0} -v {1}'.format(jar_file, info.filename[:-6])
+      output1 = subprocess.run(
+          cmd.split(),
+          stdout=subprocess.PIPE,
+          text=True,
+          check=True,
+      )
+      matches = _LANGUAGE_LEVEL_PATTERN.findall(output1.stdout)
+      if len(matches) != 1:
+        raise ValueError('Expected exactly one match but found: %s' % matches)
+      class_language_level = matches[0]
+      if class_language_level != expected_language_level:
+        invalid_entries.append(
+            '{0}: {1}'.format(info.filename, class_language_level)
+        )
+      # This can take a while so print an update.
+      print(
+          '  ({0} of {1}) Found language level {2}: {3}'.format(
+              i + 1,
+              num_classes,
+              class_language_level,
+              info.filename,
+          )
+      )
+
+  return invalid_entries
+
+
+def is_shaded_class(filename):
+  # Ignore the shaded deps because we don't really control these classes.
+  shaded_prefixes = [
+      'dagger/spi/internal/shaded/',
+      'dagger/grpc/shaded/',
+  ]
+  for shaded_prefix in shaded_prefixes:
+    if filename.startswith(shaded_prefix):
+      return True
+  return False
+
+
+if __name__ == '__main__':
+  main(sys.argv)